diff --git a/src/menu.cpp b/src/menu.cpp
index 0e71cac..b372277 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -43,6 +43,29 @@
using namespace std;
+Menu::Animation::Animation()
+ : curr(0)
+{
+}
+
+void Menu::Animation::adjust(int delta)
+{
+ curr += delta;
+}
+
+void Menu::Animation::step()
+{
+ if (curr == 0) {
+ ERROR("Computing step past animation end\n");
+ } else if (curr < 0) {
+ const int v = ((1 << 16) - curr) / 32;
+ curr = std::min(0, curr + v);
+ } else {
+ const int v = ((1 << 16) + curr) / 32;
+ curr = std::max(0, curr - v);
+ }
+}
+
Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts)
: gmenu2x(gmenu2x)
, ts(ts)
@@ -148,7 +171,18 @@ void Menu::calcSectionRange(int &leftSection, int &rightSection) {
rightSection - numSections + 1);
}
+void Menu::runAnimations() {
+ if (sectionAnimation.isRunning()) {
+ sectionAnimation.step();
+ if (!sectionAnimation.isRunning()) {
+ stopAnimating();
+ }
+ }
+}
+
void Menu::paint(Surface &s) {
+ runAnimations();
+
const uint width = s.width(), height = s.height();
Font &font = *gmenu2x->font;
SurfaceCollection &sc = gmenu2x->sc;
@@ -160,19 +194,37 @@ void Menu::paint(Surface &s) {
const int linkHeight = skinConfInt["linkHeight"];
RGBAColor &selectionBgColor = gmenu2x->skinConfColors[COLOR_SELECTION_BG];
- // Paint section headers.
+ // Apply section header animation.
int leftSection, rightSection;
calcSectionRange(leftSection, rightSection);
+ int sectionFP = sectionAnimation.currentValue();
+ int sectionDelta = (sectionFP * linkWidth + (1 << 15)) >> 16;
+ int centerSection = iSection - sectionDelta / linkWidth;
+ sectionDelta %= linkWidth;
+ if (sectionDelta < 0) {
+ rightSection++;
+ } else if (sectionDelta > 0) {
+ leftSection--;
+ }
+
+ // Paint section headers.
s.box(width / 2 - linkWidth / 2, 0, linkWidth, topBarHeight, selectionBgColor);
const uint sectionLinkPadding = (topBarHeight - 32 - font.getHeight()) / 3;
const uint numSections = sections.size();
for (int i = leftSection; i <= rightSection; i++) {
- uint j = (iSection + numSections + i) % numSections;
+ uint j = (centerSection + numSections + i) % numSections;
string sectionIcon = "skin:sections/" + sections[j] + ".png";
Surface *icon = sc.exists(sectionIcon)
? sc[sectionIcon]
: sc.skinRes("icons/section.png");
- const int x = width / 2 + i * linkWidth;
+ int x = width / 2 + i * linkWidth + sectionDelta;
+ if (i == leftSection) {
+ int t = sectionDelta > 0 ? linkWidth - sectionDelta : -sectionDelta;
+ x -= (((t * t) / linkWidth) * t) / linkWidth;
+ } else if (i == rightSection) {
+ int t = sectionDelta < 0 ? sectionDelta + linkWidth : sectionDelta;
+ x += (((t * t) / linkWidth) * t) / linkWidth;
+ }
icon->blit(&s, x - 16, sectionLinkPadding, 32, 32);
s.write(&font, sections[j], x, topBarHeight - sectionLinkPadding,
Font::HAlignCenter, Font::VAlignBottom);
@@ -318,11 +370,15 @@ vector *Menu::sectionLinks(int i) {
}
void Menu::decSectionIndex() {
- setSectionIndex(iSection-1);
+ sectionAnimation.adjust(-1 << 16);
+ startAnimating();
+ setSectionIndex(iSection - 1);
}
void Menu::incSectionIndex() {
- setSectionIndex(iSection+1);
+ sectionAnimation.adjust(1 << 16);
+ startAnimating();
+ setSectionIndex(iSection + 1);
}
int Menu::selSectionIndex() {
diff --git a/src/menu.h b/src/menu.h
index f580688..32f82dc 100644
--- a/src/menu.h
+++ b/src/menu.h
@@ -42,6 +42,17 @@ Handles the menu structure
*/
class Menu : public Layer {
private:
+ class Animation {
+ public:
+ Animation();
+ bool isRunning() { return curr != 0; }
+ int currentValue() { return curr; }
+ void adjust(int delta);
+ void step();
+ private:
+ int curr;
+ };
+
GMenu2X *gmenu2x;
Touchscreen &ts;
std::unique_ptr btnContextMenu;
@@ -52,6 +63,10 @@ private:
uint linkColumns, linkRows;
+ Animation sectionAnimation;
+
+ void runAnimations();
+
/**
* Determine which section headers are visible.
* The output values are relative to the middle section at 0.