1
0
mirror of git://projects.qi-hardware.com/gmenu2x.git synced 2024-07-02 18:31:04 +03:00

Converted the context menu to a Layer

This fixes a bug with the captured background being wrong when using
double buffering. Also it ensures that for example the clock in the
status bar is updated when the context menu is open.
This commit is contained in:
Maarten ter Huurne 2013-08-11 23:46:04 +02:00
parent 945e29986a
commit 76117663ff
6 changed files with 238 additions and 169 deletions

View File

@ -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@

181
src/contextmenu.cpp Normal file
View File

@ -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 <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;
}

43
src/contextmenu.h Normal file
View File

@ -0,0 +1,43 @@
// Various authors.
// License: GPL version 2 or later.
#ifndef __CONTEXTMENU_H__
#define __CONTEXTMENU_H__
#include "layer.h"
#include <SDL.h>
#include <memory>
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<std::shared_ptr<MenuOption>> options;
SDL_Rect box;
int fadeAlpha;
int selected;
long tickStart;
};
#endif // __CONTEXTMENU_H__

View File

@ -81,13 +81,6 @@
#include <sys/mman.h>
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<shared_ptr<MenuOption>> options;
LinkApp* app = menu->selLinkApp();
options.push_back(make_shared<MenuOption>(
tr.translate("Add link in $1", menu->selSection().c_str(), NULL),
BIND(&GMenu2X::addLink)));
if (app && !app->getManual().empty()) {
options.push_back(make_shared<MenuOption>(
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<MenuOption>(
tr.translate("Edit $1", app->getTitle().c_str(), NULL),
BIND(&GMenu2X::editLink)));
}
#ifdef HAVE_LIBOPK
if (!app->isOpk())
#endif
{
options.push_back(make_shared<MenuOption>(
tr.translate("Delete $1 link", app->getTitle().c_str(), NULL),
BIND(&GMenu2X::deleteLink)));
}
}
options.push_back(make_shared<MenuOption>(
tr["Add section"], BIND(&GMenu2X::addSection)));
options.push_back(make_shared<MenuOption>(
tr["Rename section"], BIND(&GMenu2X::renameSection)));
options.push_back(make_shared<MenuOption>(
tr["Delete section"], BIND(&GMenu2X::deleteSection)));
options.push_back(make_shared<MenuOption>(
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<Uint16>(font->getTextWidth(option->text)));
}
box.w += 23;
box.x = halfX - box.w / 2;
box.y = halfY - box.h / 2;
SDL_Rect selbox = {
static_cast<Sint16>(box.x + 4),
0,
static_cast<Uint16>(box.w - 8),
static_cast<Uint16>(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<ContextMenu>(*this, *menu));
}
void GMenu2X::changeWallpaper() {

View File

@ -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<std::string>* directories, std::vector<std::string>* 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

View File

@ -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;