Root/
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 | |
15 | struct 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 | |
22 | ContextMenu::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 | |
100 | bool 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 | |
109 | void 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 | |
138 | bool 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 | |
161 | bool 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 |
Branches:
install_locations
master
opkrun
packages