Root/src/contextmenu.cpp

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

Archive Download this file



interactive