Root/src/contextmenu.cpp

1// Various authors.
2// License: GPL version 2 or later.
3
4#include "contextmenu.h"
5
6#include "delegate.h"
7#include "gmenu2x.h"
8#include "linkapp.h"
9#include "menu.h"
10#include "utilities.h"
11
12#include <algorithm>
13
14
15struct ContextMenu::MenuOption {
16    MenuOption(std::string text, function_t action)
17        : text(text), action(action) {}
18    std::string text;
19    function_t action;
20};
21
22ContextMenu::ContextMenu(GMenu2X &gmenu2x, Menu &menu)
23    : gmenu2x(gmenu2x)
24    , menu(menu)
25    , selected(0)
26{
27    Translator &tr = gmenu2x.tr;
28    Font *font = gmenu2x.font;
29    LinkApp* app = menu.selLinkApp();
30
31    // Init menu options:
32
33    options.push_back(std::make_shared<MenuOption>(
34            tr.translate("Add link in $1", menu.selSection().c_str(), NULL),
35            std::bind(&GMenu2X::addLink, &gmenu2x)));
36
37    if (app && !app->getManual().empty()) {
38        options.push_back(std::make_shared<MenuOption>(
39                tr.translate("Show manual of $1", app->getTitle().c_str(), NULL),
40                std::bind(&GMenu2X::showManual, &gmenu2x)));
41    }
42
43    if (app && app->isEditable()) {
44
45        /* FIXME(percuei): This permits to mask the "Edit link" entry
46         * on the contextual menu in case CPUFREQ support is
47         * not compiled in and the link corresponds to an OPK.
48         * This is not a good idea as it'll break things if
49         * a new config option is added to the contextual menu.
50         */
51        if (!app->isOpk()
52#if defined(ENABLE_CPUFREQ)
53                || true
54#endif
55                || !app->getSelectorDir().empty()
56                ) {
57            options.push_back(std::make_shared<MenuOption>(
58                    tr.translate("Edit $1", app->getTitle().c_str(), NULL),
59                    std::bind(&GMenu2X::editLink, &gmenu2x)));
60        }
61        if (!app->isOpk()) {
62            options.push_back(std::make_shared<MenuOption>(
63                    tr.translate("Delete $1 link", app->getTitle().c_str(), NULL),
64                    std::bind(&GMenu2X::deleteLink, &gmenu2x)));
65        }
66    }
67
68    options.push_back(std::make_shared<MenuOption>(
69            tr["Add section"],
70            std::bind(&GMenu2X::addSection, &gmenu2x)));
71    options.push_back(std::make_shared<MenuOption>(
72            tr["Rename section"],
73            std::bind(&GMenu2X::renameSection, &gmenu2x)));
74    options.push_back(std::make_shared<MenuOption>(
75            tr["Delete section"],
76            std::bind(&GMenu2X::deleteSection, &gmenu2x)));
77    options.push_back(std::make_shared<MenuOption>(
78            tr["Scan for applications and games"],
79            std::bind(&GMenu2X::scanner, &gmenu2x)));
80
81    // Compute bounding box.
82    int w = 0;
83    for (auto option : options) {
84        w = std::max(w, font->getTextWidth(option->text));
85    }
86    w += 23;
87    const int h = (font->getHeight() + 2) * options.size() + 8;
88    box = {
89        static_cast<Sint16>((gmenu2x.resX - w) / 2),
90        static_cast<Sint16>((gmenu2x.resY - h) / 2),
91        static_cast<Uint16>(w),
92        static_cast<Uint16>(h)
93    };
94
95    // Init background fade animation.
96    tickStart = SDL_GetTicks();
97    fadeAlpha = 0;
98}
99
100bool ContextMenu::runAnimations()
101{
102    if (fadeAlpha < 200) {
103        const long tickNow = SDL_GetTicks();
104        fadeAlpha = intTransition(0, 200, tickStart, 500, tickNow);
105    }
106    return fadeAlpha < 200;
107}
108
109void ContextMenu::paint(Surface &s)
110{
111    Font *font = gmenu2x.font;
112
113    // Darken background.
114    s.box(0, 0, gmenu2x.resX, gmenu2x.resY, 0, 0, 0, fadeAlpha);
115
116    // Draw popup box.
117    s.box(box, gmenu2x.skinConfColors[COLOR_MESSAGE_BOX_BG]);
118    s.rectangle(box.x + 2, box.y + 2, box.w - 4, box.h - 4,
119            gmenu2x.skinConfColors[COLOR_MESSAGE_BOX_BORDER]);
120
121    // Draw selection background.
122    const int h = font->getHeight();
123    SDL_Rect selbox = {
124        static_cast<Sint16>(box.x + 4),
125        static_cast<Sint16>(box.y + 4 + (h + 2) * selected),
126        static_cast<Uint16>(box.w - 8),
127        static_cast<Uint16>(h + 2)
128    };
129    s.box(selbox, gmenu2x.skinConfColors[COLOR_MESSAGE_BOX_SELECTION]);
130
131    // List options.
132    for (uint i = 0; i < options.size(); i++) {
133        s.write(font, options[i]->text, box.x + 12, box.y + 5 + (h + 2) * i,
134                Font::HAlignLeft, Font::VAlignTop);
135    }
136}
137
138bool ContextMenu::handleButtonPress(InputManager::Button button) {
139    switch (button) {
140        case InputManager::MENU:
141            dismiss();
142            break;
143        case InputManager::UP:
144            selected--;
145            if (selected < 0) selected = options.size() - 1;
146            break;
147        case InputManager::DOWN:
148            selected++;
149            if (selected >= static_cast<int>(options.size())) selected = 0;
150            break;
151        case InputManager::ACCEPT:
152            options[selected]->action();
153            dismiss();
154            break;
155        default:
156            break;
157    }
158    return true;
159}
160
161bool ContextMenu::handleTouchscreen(Touchscreen &ts) {
162    if (ts.inRect(box)) {
163        int i = std::max(0, std::min(static_cast<int>(options.size()) - 1,
164                (ts.getY() - (box.y + 4)) / (gmenu2x.font->getHeight() + 2)));
165        if (ts.released()) {
166            options[i]->action();
167            dismiss();
168        } else if (ts.pressed()) {
169            selected = i;
170        }
171    } else {
172        if (ts.released()) {
173            dismiss();
174        }
175    }
176    return true;
177}
178

Archive Download this file



interactive