Display Updates and Mini Menu (#1254)

* Initial commit for mini config menu

* Implemented menu options and prepared methods for save functionality.

* Removed stdio init

* Added screen saver mode in addition to display timeout. Default is Display Off (original behavior).
Added "snow", "bounce", "pipes", and "toast" screen savers.
drawSprite can now scale sprite data.

* Added VLX and Sega 2P 6 button layout variants
Added button layout orientation feature to switch layouts for handedness
Updated Display config page to update enum definitions for i18n

* Added menu navigation helper function in prep for event system
Added layout and menu action locale strings

* Adjustments to Arcade, Button Angled, and Capcom layouts to make them less likely to cut off on SH110X displays.

* Improved screen autodetection and manual override

* Adjusting conflicts

* Conflicts part deux

* Conflicts with enums

* One more time with conflicts

* Button layout screen conflicts with change between profile banner and generic banner

* Remove profile variables

* Mostly implemented menu navigation, config change storage, and reboot events

* Full menu navigation implementation.
Added timer for reboot cases.

* Increased storage size to 32k

* Added options to disable different components of the status bar on ButtonLayoutScreen.
Removed & deprecated input history addon remnants and migrated to Display options proper.

* Remove deprecated input history init

* Set default Display tab to Hardware

* _Actually_ set default Display tab to Hardware

* Adjust bounce velocity
This commit is contained in:
Mike Parks
2025-01-23 17:27:09 -08:00
committed by GitHub
parent aaeff00a15
commit 69f6d213e1
54 changed files with 2311 additions and 771 deletions

View File

@@ -186,6 +186,7 @@ src/display/ui/elements/GPWidget.cpp
src/display/ui/elements/GPButton.cpp
src/display/ui/elements/GPLever.cpp
src/display/ui/elements/GPLabel.cpp
src/display/ui/elements/GPMenu.cpp
src/display/ui/elements/GPScreen.cpp
src/display/ui/elements/GPShape.cpp
src/display/ui/elements/GPSprite.cpp
@@ -196,6 +197,7 @@ src/display/ui/screens/PinViewerScreen.cpp
src/display/ui/screens/RestartScreen.cpp
src/display/ui/screens/StatsScreen.cpp
src/display/ui/screens/SplashScreen.cpp
src/display/ui/screens/DisplaySaverScreen.cpp
src/display/GPGFX.cpp
src/display/GPGFX_UI.cpp
src/drivermanager.cpp

View File

@@ -106,6 +106,14 @@
#define INPUT_HISTORY_ROW 7
#endif
#ifndef DISPLAY_SAVER_MODE
#define DISPLAY_SAVER_MODE DISPLAY_SAVER_DISPLAY_OFF
#endif
#ifndef DISPLAY_LAYOUT_ORIENTATION
#define DISPLAY_LAYOUT_ORIENTATION BUTTON_ORIENTATION_DEFAULT
#endif
#ifndef DEFAULT_SPLASH
#define DEFAULT_SPLASH \
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
@@ -188,8 +196,9 @@ public:
virtual std::string name() { return DisplayName; }
void handleSystemRestart(GPEvent* e);
void handleMenuNavigation(GPEvent* e);
private:
bool updateDisplayScreen();
bool updateDisplayScreen();
void drawStatusBar(Gamepad*);
void initMenu(char**);
bool pressedUp();
@@ -209,11 +218,15 @@ private:
GPGFX* gpDisplay;
GPScreen* gpScreen;
DisplayMode currDisplayMode;
DisplayMode prevDisplayMode;
DisplayMode prevDisplayMode;
bool turnOffWhenSuspended;
uint32_t bootMode;
GPGFX_DisplayTypeOptions gpOptions;
DisplaySaverMode displaySaverMode;
GPGFX_DisplayTypeOptions gpOptions;
GamepadButtonMapping *mapMenuToggle;
};
#endif

View File

@@ -129,20 +129,30 @@
{GP_ELEMENT_BTN_BUTTON, {119,33, 5, 5, 1, 1, GAMEPAD_MASK_S2, GP_SHAPE_ELLIPSE}}\
}
#define BUTTON_GROUP_VLXB_6B {\
{GP_ELEMENT_BTN_BUTTON, {50, 31, 7, 7, 1, 1, GAMEPAD_MASK_B3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {66, 24, 7, 7, 1, 1, GAMEPAD_MASK_B4, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {82, 24, 7, 7, 1, 1, GAMEPAD_MASK_R1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {45, 47, 7, 7, 1, 1, GAMEPAD_MASK_B1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {61, 40, 7, 7, 1, 1, GAMEPAD_MASK_B2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {77, 40, 7, 7, 1, 1, GAMEPAD_MASK_R2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {119,33, 5, 5, 1, 1, GAMEPAD_MASK_S2, GP_SHAPE_ELLIPSE}}\
}
#define BUTTON_GROUP_FIGHTBOARD {\
{GP_ELEMENT_BTN_BUTTON, {69, 27, 7, 7, 1, 1, GAMEPAD_MASK_B3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {86, 18, 7, 7, 1, 1, GAMEPAD_MASK_B4, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {103,18, 7, 7, 1, 1, GAMEPAD_MASK_R1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {120,18, 7, 7, 1, 1, GAMEPAD_MASK_L1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {69, 43, 7, 7, 1, 1, GAMEPAD_MASK_B1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {86, 35, 7, 7, 1, 1, GAMEPAD_MASK_B2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {103,35, 7, 7, 1, 1, GAMEPAD_MASK_R2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {120,35, 7, 7, 1, 1, GAMEPAD_MASK_L2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {84, 47, 3, 3, 1, 1, GAMEPAD_MASK_L3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {94, 47, 3, 3, 1, 1, GAMEPAD_MASK_S1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {103,47, 3, 3, 1, 1, GAMEPAD_MASK_A1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {112,47, 3, 3, 1, 1, GAMEPAD_MASK_S2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {122,47, 3, 3, 1, 1, GAMEPAD_MASK_R3, GP_SHAPE_ELLIPSE}}\
{GP_ELEMENT_BTN_BUTTON, {67, 27, 7, 7, 1, 1, GAMEPAD_MASK_B3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {84, 18, 7, 7, 1, 1, GAMEPAD_MASK_B4, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {101,18, 7, 7, 1, 1, GAMEPAD_MASK_R1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {118,18, 7, 7, 1, 1, GAMEPAD_MASK_L1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {67, 43, 7, 7, 1, 1, GAMEPAD_MASK_B1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {84, 35, 7, 7, 1, 1, GAMEPAD_MASK_B2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {101,35, 7, 7, 1, 1, GAMEPAD_MASK_R2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {118,35, 7, 7, 1, 1, GAMEPAD_MASK_L2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {82, 47, 3, 3, 1, 1, GAMEPAD_MASK_L3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {92, 47, 3, 3, 1, 1, GAMEPAD_MASK_S1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {101,47, 3, 3, 1, 1, GAMEPAD_MASK_A1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {110,47, 3, 3, 1, 1, GAMEPAD_MASK_S2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {120,47, 3, 3, 1, 1, GAMEPAD_MASK_R3, GP_SHAPE_ELLIPSE}}\
}
#define BUTTON_GROUP_VEWLIX7 {\
@@ -166,6 +176,15 @@
{GP_ELEMENT_BTN_BUTTON, {111,46, 8, 8, 1, 1, GAMEPAD_MASK_L2, GP_SHAPE_ELLIPSE}}\
}
#define BUTTON_GROUP_SEGA_2P_6B {\
{GP_ELEMENT_BTN_BUTTON, {57, 34, 8, 8, 1, 1, GAMEPAD_MASK_B3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {75, 24, 8, 8, 1, 1, GAMEPAD_MASK_B4, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {93, 24, 8, 8, 1, 1, GAMEPAD_MASK_R1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {57, 52, 8, 8, 1, 1, GAMEPAD_MASK_B1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {75, 42, 8, 8, 1, 1, GAMEPAD_MASK_B2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {93, 42, 8, 8, 1, 1, GAMEPAD_MASK_R2, GP_SHAPE_ELLIPSE}}\
}
#define BUTTON_GROUP_NOIR8 {\
{GP_ELEMENT_BTN_BUTTON, {57, 33, 8, 8, 1, 1, GAMEPAD_MASK_B3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {75, 24, 8, 8, 1, 1, GAMEPAD_MASK_B4, GP_SHAPE_ELLIPSE}},\
@@ -178,14 +197,14 @@
}
#define BUTTON_GROUP_CAPCOM {\
{GP_ELEMENT_BTN_BUTTON, {64, 28, 8, 8, 1, 1, GAMEPAD_MASK_B3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {82, 28, 8, 8, 1, 1, GAMEPAD_MASK_B4, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {100,28, 8, 8, 1, 1, GAMEPAD_MASK_R1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {118,28, 8, 8, 1, 1, GAMEPAD_MASK_L1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {64, 46, 8, 8, 1, 1, GAMEPAD_MASK_B1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {82, 46, 8, 8, 1, 1, GAMEPAD_MASK_B2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {100,46, 8, 8, 1, 1, GAMEPAD_MASK_R2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {118,46, 8, 8, 1, 1, GAMEPAD_MASK_L2, GP_SHAPE_ELLIPSE}}\
{GP_ELEMENT_BTN_BUTTON, {62, 28, 8, 8, 1, 1, GAMEPAD_MASK_B3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {80, 28, 8, 8, 1, 1, GAMEPAD_MASK_B4, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {98, 28, 8, 8, 1, 1, GAMEPAD_MASK_R1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {116,28, 8, 8, 1, 1, GAMEPAD_MASK_L1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {62, 46, 8, 8, 1, 1, GAMEPAD_MASK_B1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {80, 46, 8, 8, 1, 1, GAMEPAD_MASK_B2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {98, 46, 8, 8, 1, 1, GAMEPAD_MASK_R2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {116,46, 8, 8, 1, 1, GAMEPAD_MASK_L2, GP_SHAPE_ELLIPSE}}\
}
#define BUTTON_GROUP_CAPCOM6 {\
@@ -209,25 +228,25 @@
}
#define BUTTON_GROUP_WASD_BUTTONS {\
{GP_ELEMENT_BTN_BUTTON, {69, 28, 7, 7, 1, 1, GAMEPAD_MASK_B3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {86, 24, 7, 7, 1, 1, GAMEPAD_MASK_B4, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {103,24, 7, 7, 1, 1, GAMEPAD_MASK_R1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {120,28, 7, 7, 1, 1, GAMEPAD_MASK_L1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {63, 45, 7, 7, 1, 1, GAMEPAD_MASK_B1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {80, 41, 7, 7, 1, 1, GAMEPAD_MASK_B2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {97, 41, 7, 7, 1, 1, GAMEPAD_MASK_R2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {114,45, 7, 7, 1, 1, GAMEPAD_MASK_L2, GP_SHAPE_ELLIPSE}}\
{GP_ELEMENT_BTN_BUTTON, {67, 28, 7, 7, 1, 1, GAMEPAD_MASK_B3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {84, 24, 7, 7, 1, 1, GAMEPAD_MASK_B4, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {101,24, 7, 7, 1, 1, GAMEPAD_MASK_R1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {118,28, 7, 7, 1, 1, GAMEPAD_MASK_L1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {61, 45, 7, 7, 1, 1, GAMEPAD_MASK_B1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {78, 41, 7, 7, 1, 1, GAMEPAD_MASK_B2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {95, 41, 7, 7, 1, 1, GAMEPAD_MASK_R2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {112,45, 7, 7, 1, 1, GAMEPAD_MASK_L2, GP_SHAPE_ELLIPSE}}\
}
#define BUTTON_GROUP_ARCADE_BUTTONS {\
{GP_ELEMENT_BTN_BUTTON, {64, 28, 8, 8, 1, 1, GAMEPAD_MASK_B3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {82, 24, 8, 8, 1, 1, GAMEPAD_MASK_B4, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {100,24, 8, 8, 1, 1, GAMEPAD_MASK_R1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {118,28, 8, 8, 1, 1, GAMEPAD_MASK_L1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {59, 46, 8, 8, 1, 1, GAMEPAD_MASK_B1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {77, 42, 8, 8, 1, 1, GAMEPAD_MASK_B2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {95, 42, 8, 8, 1, 1, GAMEPAD_MASK_R2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {113,46, 8, 8, 1, 1, GAMEPAD_MASK_L2, GP_SHAPE_ELLIPSE}}\
{GP_ELEMENT_BTN_BUTTON, {62, 28, 8, 8, 1, 1, GAMEPAD_MASK_B3, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {80, 24, 8, 8, 1, 1, GAMEPAD_MASK_B4, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {98, 24, 8, 8, 1, 1, GAMEPAD_MASK_R1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {116,28, 8, 8, 1, 1, GAMEPAD_MASK_L1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {57, 46, 8, 8, 1, 1, GAMEPAD_MASK_B1, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {75, 42, 8, 8, 1, 1, GAMEPAD_MASK_B2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {93, 42, 8, 8, 1, 1, GAMEPAD_MASK_R2, GP_SHAPE_ELLIPSE}},\
{GP_ELEMENT_BTN_BUTTON, {111,46, 8, 8, 1, 1, GAMEPAD_MASK_L2, GP_SHAPE_ELLIPSE}}\
}
#define BUTTON_GROUP_STICKLESS13A {\

View File

@@ -12,7 +12,7 @@ class GPGFX {
void init(GPGFX_DisplayTypeOptions options);
GPGFX_DisplayTypeOptions getAvailableDisplay();
GPGFX_DisplayTypeOptions getAvailableDisplay(GPGFX_DisplayType displayType);
GPGFX_DisplayBase* getDriver() { return displayDriver; }
@@ -20,6 +20,7 @@ class GPGFX {
void clearScreen();
void render();
uint32_t getPixel(uint16_t x, uint16_t y);
void drawPixel(uint16_t x, uint16_t y, uint32_t color);
void drawText(uint16_t x, uint16_t y, std::string text, uint8_t invert = 0);
void drawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint32_t color, uint8_t filled);
@@ -27,9 +28,11 @@ class GPGFX {
void drawEllipse(uint16_t x, uint16_t y, uint32_t radiusX, uint32_t radiusY, uint32_t color, uint8_t filled);
void drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled, double rotationAngle = 0);
void drawPolygon(uint16_t x, uint16_t y, uint16_t radius, uint16_t sides, uint32_t color, uint8_t filled, double rotation = 0);
void drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority);
void drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority, double scale = 1.0);
private:
GPGFX_DisplayBase* displayDriver = nullptr;
bool detectDisplay(GPGFX_DisplayTypeOptions* display, GPGFX_DisplayType displayType);
};
#endif

View File

@@ -6,6 +6,7 @@ enum DisplayMode {
BUTTONS,
SPLASH,
PIN_VIEWER,
DISPLAY_SAVER,
STATS,
MAIN_MENU,
RESTART
@@ -13,6 +14,7 @@ enum DisplayMode {
#include "ui/screens/ButtonLayoutScreen.h"
#include "ui/screens/ConfigScreen.h"
#include "ui/screens/DisplaySaverScreen.h"
#include "ui/screens/MainMenuScreen.h"
#include "ui/screens/PinViewerScreen.h"
#include "ui/screens/RestartScreen.h"

View File

@@ -5,10 +5,13 @@
#include <functional>
#include <vector>
typedef struct {
typedef struct MenuEntry {
std::string label;
uint8_t* icon;
std::vector<MenuEntry>* submenu;
std::function<int32_t()> currentValue;
std::function<void()> action;
int32_t optionValue = -1;
} MenuEntry;
typedef struct {

View File

@@ -8,6 +8,7 @@
#include "ui/elements/GPScreen.h"
#include "ui/elements/GPShape.h"
#include "ui/elements/GPSprite.h"
#include "ui/elements/GPMenu.h"
#include "GPGFX_UI_screens.h"

View File

@@ -23,7 +23,7 @@ class GPButton : public GPWidget {
double _angle = 0;
double _angleEnd = 0;
bool _closed = false;
int16_t _inputMask = -1;
int32_t _inputMask = -1;
bool _inputDirection = false;
GPElement _inputType = GP_ELEMENT_BTN_BUTTON;
GPShape_Type _shape = GP_SHAPE_ELLIPSE;

View File

@@ -0,0 +1,31 @@
#ifndef _GPMENU_H_
#define _GPMENU_H_
#include "GPWidget.h"
#include "GPShape.h"
#include "GPGFX_UI_types.h"
class GPMenu : public GPShape {
public:
void draw();
GPMenu* setMenuSize(uint16_t sizeX, uint16_t sizeY) { this->menuSizeX = sizeX; this->menuSizeY = sizeY; return this; }
uint16_t getDataSize() { return this->menuEntryData->size(); };
void setIndex(uint16_t pos) { this->menuIndex = pos; };
uint16_t getIndex() { return this->menuIndex; };
void setMenuData(std::vector<MenuEntry>* menu) { this->menuEntryData = menu; };
void setMenuTitle(std::string title) { this->menuTitle = title; };
private:
uint16_t menuSizeX = 0;
uint16_t menuSizeY = 0;
uint16_t menuLines = 15;
uint16_t menuIndex = 0;
std::vector<MenuEntry>* menuEntryData;
std::string menuTitle;
};
#endif

View File

@@ -28,6 +28,9 @@ class GPWidget : public GPGFX_UI {
double getScaleX() { return ((double)(this->getViewport().right - this->getViewport().left) / (double)(getRenderer()->getDriver()->getMetrics()->width)); }
double getScaleY() { return ((double)(this->getViewport().bottom - this->getViewport().top) / (double)(getRenderer()->getDriver()->getMetrics()->height)); }
void setVisibility(bool visible) { this->_visibility = visible; }
bool getVisibility() { return this->_visibility; }
protected:
uint16_t x = 0;
uint16_t y = 0;
@@ -36,6 +39,7 @@ class GPWidget : public GPGFX_UI {
uint16_t fillColor = 0;
uint16_t _ID;
uint16_t _priority = 0;
bool _visibility = true;
GPViewport _viewport;
};

View File

@@ -7,6 +7,9 @@
#include <deque>
#include <array>
#include <functional>
#include <algorithm>
#include <cctype>
#include <locale>
#include "layoutmanager.h"
#include "GPGFX_UI_widgets.h"
#include "GPGFX_UI_layouts.h"
@@ -158,9 +161,18 @@ class ButtonLayoutScreen : public GPScreen {
uint8_t prevProfileNumber = 0;
ButtonLayoutParamsLeft prevLeftOptions;
ButtonLayoutParamsRight prevRightOptions;
ButtonLayoutOrientation prevOrientation;
bool macroEnabled;
bool showInputMode = true;
bool showTurboMode = true;
bool showDpadMode = true;
bool showSocdMode = true;
bool showMacroMode = true;
bool showProfileMode = false;
void trim(std::string &s);
uint16_t map(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max);
void processInputHistory();
bool compareCustomLayouts();

View File

@@ -0,0 +1,62 @@
#ifndef _DISPLAYSAVERSCREEN_H_
#define _DISPLAYSAVERSCREEN_H_
#include <vector>
#include "GPGFX_UI_widgets.h"
#include "bitmaps.h"
const uint8_t SCREEN_WIDTH = 128;
const uint8_t SCREEN_HEIGHT = 64;
class DisplaySaverScreen : public GPScreen {
public:
DisplaySaverScreen() {}
DisplaySaverScreen(GPGFX* renderer) { setRenderer(renderer); }
virtual int8_t update();
virtual void init();
virtual void shutdown();
protected:
virtual void drawScreen();
uint16_t prevButtonState = 0;
DisplaySaverMode displaySaverMode;
// snow screen
uint8_t snowflakeSpeeds[SCREEN_WIDTH][SCREEN_HEIGHT] = {};
int8_t snowflakeDrift[SCREEN_WIDTH][SCREEN_HEIGHT] = {};
void initSnowScene();
void drawSnowScene();
// bounce
uint16_t bounceSpriteX = 0;
uint16_t bounceSpriteY = 0;
uint16_t bounceSpriteWidth = 128;
uint16_t bounceSpriteHeight = 35;
double bounceSpriteVelocityX = 1;
double bounceSpriteVelocityY = 1;
double bounceScale = 0.5;
void drawBounceScene();
// pipes
void drawPipeScene();
// toaster
struct ToastParams {
uint8_t* image;
uint16_t width;
uint16_t height;
double scale;
int16_t x;
int16_t y;
int16_t dx;
int16_t dy;
};
std::vector<ToastParams> toasters;
uint16_t numberOfToasters = 10;
uint16_t toasterSpriteWidth = 43;
uint16_t toasterSpriteHeight = 39;
void initToasters();
void drawToasterScene();
};
#endif

View File

@@ -3,6 +3,38 @@
#include "GPGFX_UI_widgets.h"
#include "GPGFX_UI_types.h"
#include "enums.pb.h"
#include "AnimationStation.hpp"
#include "eventmanager.h"
#define INPUT_MODE_XINPUT_NAME "XInput"
#define INPUT_MODE_SWITCH_NAME "Nintendo Switch"
#define INPUT_MODE_PS3_NAME "PS3"
#define INPUT_MODE_KEYBOARD_NAME "Keyboard"
#define INPUT_MODE_PS4_NAME "PS4"
#define INPUT_MODE_XBONE_NAME "Xbox One"
#define INPUT_MODE_MDMINI_NAME "Sega Genesis Mini"
#define INPUT_MODE_NEOGEO_NAME "NEOGEO mini"
#define INPUT_MODE_PCEMINI_NAME "PC Engine Mini"
#define INPUT_MODE_EGRET_NAME "EGRET II mini"
#define INPUT_MODE_ASTRO_NAME "ASTROCITY Mini"
#define INPUT_MODE_PSCLASSIC_NAME "Playstation Classic"
#define INPUT_MODE_XBOXORIGINAL_NAME "Original Xbox"
#define INPUT_MODE_PS5_NAME "PS5"
#define INPUT_MODE_GENERIC_NAME "Generic HID"
#define INPUT_MODE_CONFIG_NAME "Web Config"
#define SOCD_MODE_UP_PRIORITY_NAME "Up Priority"
#define SOCD_MODE_NEUTRAL_NAME "Neutral"
#define SOCD_MODE_SECOND_INPUT_PRIORITY_NAME "Last Win"
#define SOCD_MODE_FIRST_INPUT_PRIORITY_NAME "First Win"
#define SOCD_MODE_BYPASS_NAME "Off"
#define DPAD_MODE_DIGITAL_NAME "D-Pad"
#define DPAD_MODE_LEFT_ANALOG_NAME "Left Analog"
#define DPAD_MODE_RIGHT_ANALOG_NAME "Right Analog"
#define MAIN_MENU_NAME "GP2040-CE Mini Menu"
class MainMenuScreen : public GPScreen {
public:
@@ -12,6 +44,30 @@ class MainMenuScreen : public GPScreen {
virtual int8_t update();
virtual void init();
virtual void shutdown();
void testMenu() {}
void saveAndExit();
int32_t modeValue();
void selectInputMode();
int32_t currentInputMode();
void selectDPadMode();
int32_t currentDpadMode();
void selectSOCDMode();
int32_t currentSOCDMode();
void selectProfile();
int32_t currentProfile();
void selectFocusMode();
int32_t currentFocusMode();
void selectTurboMode();
int32_t currentTurboMode();
void updateMenuNavigation(GpioAction action);
protected:
virtual void drawScreen();
private:
@@ -19,7 +75,84 @@ class MainMenuScreen : public GPScreen {
bool isPressed = false;
uint32_t checkDebounce;
std::vector<MenuEntry>* currentMenu;
std::vector<MenuEntry>* previousMenu;
uint16_t prevButtonState = 0;
Mask_t prevValues;
GPMenu* gpMenu;
bool screenIsPrompting = false;
bool promptChoice = false;
int8_t exitToScreenBeforePrompt = -1;
int8_t exitToScreen = -1;
GamepadButtonMapping *mapMenuUp;
GamepadButtonMapping *mapMenuDown;
GamepadButtonMapping *mapMenuLeft;
GamepadButtonMapping *mapMenuRight;
GamepadButtonMapping *mapMenuSelect;
GamepadButtonMapping *mapMenuBack;
GamepadButtonMapping *mapMenuToggle;
void saveOptions();
void resetOptions();
bool changeRequiresReboot = false;
bool changeRequiresSave = false;
#define INPUT_MODE_ENTRIES(name, value) {name##_NAME, NULL, nullptr, std::bind(&MainMenuScreen::currentInputMode, this), std::bind(&MainMenuScreen::selectInputMode, this), value},
#define DPAD_MODE_ENTRIES(name, value) {name##_NAME, NULL, nullptr, std::bind(&MainMenuScreen::currentDpadMode, this), std::bind(&MainMenuScreen::selectDPadMode, this), value},
#define SOCD_MODE_ENTRIES(name, value) {name##_NAME, NULL, nullptr, std::bind(&MainMenuScreen::currentSOCDMode, this), std::bind(&MainMenuScreen::selectSOCDMode, this), value},
std::vector<MenuEntry> inputModeMenu = {
InputMode_VALUELIST(INPUT_MODE_ENTRIES)
};
InputMode prevInputMode;
InputMode updateInputMode;
std::vector<MenuEntry> dpadModeMenu = {
DpadMode_VALUELIST(DPAD_MODE_ENTRIES)
};
DpadMode prevDpadMode;
DpadMode updateDpadMode;
std::vector<MenuEntry> socdModeMenu = {
SOCDMode_VALUELIST(SOCD_MODE_ENTRIES)
};
SOCDMode prevSocdMode;
SOCDMode updateSocdMode;
std::vector<MenuEntry> profilesMenu = {};
uint8_t prevProfile;
uint8_t updateProfile;
std::vector<MenuEntry> focusModeMenu = {
{"Off", NULL, nullptr, std::bind(&MainMenuScreen::currentFocusMode, this), std::bind(&MainMenuScreen::selectFocusMode, this), 0},
{"On", NULL, nullptr, std::bind(&MainMenuScreen::currentFocusMode, this), std::bind(&MainMenuScreen::selectFocusMode, this), 1},
};
bool prevFocus;
bool updateFocus;
std::vector<MenuEntry> turboModeMenu = {
{"Off", NULL, nullptr, std::bind(&MainMenuScreen::currentTurboMode, this), std::bind(&MainMenuScreen::selectTurboMode, this), 0},
{"On", NULL, nullptr, std::bind(&MainMenuScreen::currentTurboMode, this), std::bind(&MainMenuScreen::selectTurboMode, this), 1},
};
bool prevTurbo;
bool updateTurbo;
std::vector<MenuEntry> mainMenu = {
{"Input Mode", NULL, &inputModeMenu, std::bind(&MainMenuScreen::modeValue, this), std::bind(&MainMenuScreen::testMenu, this)},
{"D-Pad Mode", NULL, &dpadModeMenu, std::bind(&MainMenuScreen::modeValue, this), std::bind(&MainMenuScreen::testMenu, this)},
{"SOCD Mode", NULL, &socdModeMenu, std::bind(&MainMenuScreen::modeValue, this), std::bind(&MainMenuScreen::testMenu, this)},
{"Profile", NULL, &profilesMenu, std::bind(&MainMenuScreen::modeValue, this), std::bind(&MainMenuScreen::testMenu, this)},
{"Focus Mode", NULL, &focusModeMenu, std::bind(&MainMenuScreen::modeValue, this), std::bind(&MainMenuScreen::testMenu, this)},
{"Turbo", NULL, &turboModeMenu, std::bind(&MainMenuScreen::modeValue, this), std::bind(&MainMenuScreen::testMenu, this)},
{"Save & Exit",NULL, &saveMenu, std::bind(&MainMenuScreen::modeValue, this), std::bind(&MainMenuScreen::testMenu, this)},
};
std::vector<MenuEntry> saveMenu = {
{"Yes", NULL, nullptr, std::bind(&MainMenuScreen::modeValue, this), std::bind(&MainMenuScreen::saveAndExit, this), 1},
{"No", NULL, nullptr, std::bind(&MainMenuScreen::modeValue, this), std::bind(&MainMenuScreen::testMenu, this), 0},
};
};
#endif

View File

@@ -14,8 +14,11 @@
#include "GPEvent.h"
#include "GPGamepadEvent.h"
#include "GPEncoderEvent.h"
#include "GPMenuNavigateEvent.h"
#include "GPProfileEvent.h"
#include "GPRestartEvent.h"
#include "GPStorageSaveEvent.h"
#include "GPSystemRebootEvent.h"
#include "GPUSBHostEvent.h"
#define EVENTMGR EventManager::getInstance()
@@ -33,6 +36,9 @@ class EventManager {
return instance;
}
void init();
void clearEventHandlers();
void registerEventHandler(GPEventType eventType, EventFunction handler);
void triggerEvent(GPEvent* event);
private:

View File

@@ -0,0 +1,21 @@
#ifndef _GPMENUNAVIGATEEVENT_H_
#define _GPMENUNAVIGATEEVENT_H_
#include "system.h"
class GPMenuNavigateEvent : public GPEvent {
public:
GPMenuNavigateEvent() {}
GPMenuNavigateEvent(GpioAction action) {
this->menuAction = action;
}
~GPMenuNavigateEvent() {}
GPEventType eventType() { return this->_eventType; }
GpioAction menuAction;
private:
GPEventType _eventType = GP_EVENT_MENU_NAVIGATE;
};
#endif

View File

@@ -0,0 +1,23 @@
#ifndef _GPSTORAGESAVEEVENT_H_
#define _GPSTORAGESAVEEVENT_H_
#include "system.h"
class GPStorageSaveEvent : public GPEvent {
public:
GPStorageSaveEvent() {}
GPStorageSaveEvent(bool force, bool restart = false) {
this->forceSave = force;
this->restartAfterSave = restart;
}
~GPStorageSaveEvent() {}
GPEventType eventType() { return this->_eventType; }
bool forceSave = false;
bool restartAfterSave = false;
private:
GPEventType _eventType = GP_EVENT_STORAGE_SAVE;
};
#endif

View File

@@ -0,0 +1,21 @@
#ifndef _GPSYSTEMREBOOTEVENT_H_
#define _GPSYSTEMREBOOTEVENT_H_
#include "system.h"
class GPSystemRebootEvent : public GPEvent {
public:
GPSystemRebootEvent() {}
GPSystemRebootEvent(System::BootMode mode) {
this->bootMode = mode;
}
~GPSystemRebootEvent() {}
GPEventType eventType() { return this->_eventType; }
System::BootMode bootMode = System::BootMode::DEFAULT;
private:
GPEventType _eventType = GP_EVENT_SYSTEM_REBOOT;
};
#endif

View File

@@ -11,6 +11,7 @@
// GP2040 Classes
#include "gamepad.h"
#include "addonmanager.h"
#include "eventmanager.h"
#include "gpdriver.h"
#include "pico/types.h"
@@ -75,6 +76,13 @@ private:
// input mask, action
std::map<uint32_t, int32_t> bootActions;
bool saveRequested = false;
bool saveSuccessful = false;
void handleStorageSave(GPEvent* e);
bool rebootRequested = false;
void handleSystemReboot(GPEvent* e);
};
#endif

View File

@@ -18,6 +18,8 @@ class GPGFX_DisplayBase : public I2CDeviceBase {
virtual void clear() {}
virtual uint32_t getPixel(uint8_t x, uint8_t y) {}
virtual void drawPixel(uint8_t x, uint8_t y, uint32_t color) {}
virtual void drawText(uint8_t x, uint8_t y, std::string text, uint8_t invert = 0) {}
@@ -32,7 +34,7 @@ class GPGFX_DisplayBase : public I2CDeviceBase {
virtual void drawPolygon(uint16_t x, uint16_t y, uint16_t radius, uint16_t sides, uint32_t color, uint8_t filled, double rotation = 0) {}
virtual void drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority) {}
virtual void drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority, double scale) {}
virtual void drawBuffer(uint8_t *pBuffer) {}

View File

@@ -17,6 +17,8 @@ class GPGFX_OBD_SSD1306 : public GPGFX_DisplayBase {
void clear();
uint32_t getPixel(uint8_t x, uint8_t y);
void drawPixel(uint8_t x, uint8_t y, uint32_t color);
void drawText(uint8_t x, uint8_t y, std::string text, uint8_t invert = 0);
@@ -27,7 +29,7 @@ class GPGFX_OBD_SSD1306 : public GPGFX_DisplayBase {
void drawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color, uint8_t filled, double rotationAngle = 0);
void drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority);
void drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority, double scale = 1.0);
void drawBuffer(uint8_t *pBuffer);

View File

@@ -16,6 +16,8 @@ class GPGFX_TinySSD1306 : public GPGFX_DisplayBase {
void clear();
uint32_t getPixel(uint8_t x, uint8_t y);
void drawPixel(uint8_t x, uint8_t y, uint32_t color);
void drawText(uint8_t x, uint8_t y, std::string text, uint8_t invert = 0);
@@ -30,7 +32,7 @@ class GPGFX_TinySSD1306 : public GPGFX_DisplayBase {
void drawPolygon(uint16_t x, uint16_t y, uint16_t radius, uint16_t sides, uint32_t color, uint8_t filled, double rotation = 0);
void drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority);
void drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority, double scale = 1.0);
void drawBuffer(uint8_t *pBuffer);

View File

@@ -56,6 +56,8 @@ class LayoutManager {
std::string getButtonLayoutRightName(ButtonLayoutRight layout);
LayoutList adjustByCustomSettings(LayoutList layout, ButtonLayoutParamsCommon common, uint16_t originX = 0, uint16_t originY = 0);
LayoutList adjustByOffset(LayoutList layout, int16_t originX = 0, int16_t originY = 0);
LayoutList flipHorizontally(LayoutList layout, int16_t startX = 0, int16_t startY = 0, int16_t endX = 0, int16_t endY = 0);
// old layout methods
LayoutList drawStickless();
@@ -71,6 +73,7 @@ class LayoutManager {
LayoutList drawVewlix();
LayoutList drawVewlix7();
LayoutList drawSega2p();
LayoutList drawSega2p6b();
LayoutList drawNoir8();
LayoutList drawCapcom();
LayoutList drawCapcom6();
@@ -85,6 +88,7 @@ class LayoutManager {
LayoutList drawBlankB();
LayoutList drawVLXA();
LayoutList drawVLXB();
LayoutList drawVLXB6B();
LayoutList drawFightboard();
LayoutList drawFightboardMirrored();
LayoutList drawFightboardStick();

View File

@@ -17,6 +17,8 @@
#include "config.pb.h"
#include <atomic>
#include "pico/critical_section.h"
#include "eventmanager.h"
#include "GPStorageSaveEvent.h"
#define SI Storage::getInstance()

View File

@@ -13,8 +13,8 @@
#include <hardware/flash.h>
#include <hardware/timer.h>
#define EEPROM_SIZE_BYTES 0x4000 // Reserve 16k of flash memory (ensure this value is divisible by 256)
#define EEPROM_ADDRESS_START _u(0x101FC000) // The arduino-pico EEPROM lib starts here, so we'll do the same
#define EEPROM_SIZE_BYTES 0x8000 // Reserve 32k of flash memory (ensure this value is divisible by 256)
#define EEPROM_ADDRESS_START _u(0x101F8000) // The arduino-pico EEPROM lib starts here, so we'll do the same
// Warning: If the write wait is too long it can stall other processes
#define EEPROM_WRITE_WAIT 50 // Amount of time in ms to wait before blocking core1 and committing to flash

View File

@@ -252,6 +252,21 @@ message DisplayOptions
optional int32 displaySaverTimeout = 17;
optional bool turnOffWhenSuspended = 18;
optional DisplaySaverMode displaySaverMode = 19;
optional ButtonLayoutOrientation buttonLayoutOrientation = 20;
optional bool inputMode = 21;
optional bool turboMode = 22;
optional bool dpadMode = 23;
optional bool socdMode = 24;
optional bool macroMode = 25;
optional bool profileMode = 26;
optional bool inputHistoryEnabled = 27;
optional uint32 inputHistoryLength = 28;
optional uint32 inputHistoryCol = 29;
optional uint32 inputHistoryRow = 30;
}
message LEDOptions
@@ -751,10 +766,10 @@ message MacroOptions
message InputHistoryOptions
{
optional bool enabled = 1;
optional uint32 length = 2;
optional uint32 col = 3;
optional uint32 row = 4;
optional bool deprecatedEnabled = 1 [deprecated = true];
optional uint32 deprecatedLength = 2 [deprecated = true];
optional uint32 deprecatedCol = 3 [deprecated = true];
optional uint32 deprecatedRow = 4 [deprecated = true];
}
message RotaryPinOptions
@@ -831,7 +846,7 @@ message AddonOptions
optional TiltOptions tiltOptions = 18;
optional PSPassthroughOptions psPassthroughOptions = 19 [deprecated = true];
optional MacroOptions macroOptions = 20;
optional InputHistoryOptions inputHistoryOptions = 21;
optional InputHistoryOptions inputHistoryOptions = 21 [deprecated = true];
optional XBOnePassthroughOptions xbonePassthroughOptions = 22 [deprecated = true];
optional AnalogADS1256Options analogADS1256Options = 23;
optional RotaryOptions rotaryOptions = 24;

View File

@@ -84,6 +84,8 @@ enum ButtonLayoutRight
BUTTON_LAYOUT_6GAWD_ALLBUTTON_B = 35;
BUTTON_LAYOUT_6GAWD_ALLBUTTONPLUS_B = 36;
BUTTON_LAYOUT_STICKLESS_R16B = 37;
BUTTON_LAYOUT_VLXB_6B = 38;
BUTTON_LAYOUT_SEGA2P_6B = 39;
}
enum SplashMode
@@ -262,7 +264,15 @@ enum GpioAction
BUTTON_PRESS_INPUT_REVERSE = 69;
SUSTAIN_FOCUS_MODE = 70;
SUSTAIN_4_8_WAY_MODE = 71;
SUSTAIN_4_8_WAY_MODE = 71;
MENU_NAVIGATION_UP = 72;
MENU_NAVIGATION_DOWN = 73;
MENU_NAVIGATION_LEFT = 74;
MENU_NAVIGATION_RIGHT = 75;
MENU_NAVIGATION_SELECT = 76;
MENU_NAVIGATION_BACK = 77;
MENU_NAVIGATION_TOGGLE = 78;
}
enum GpioDirection
@@ -321,6 +331,13 @@ enum GamepadHotkey
HOTKEY_DPAD_RIGHT = 41;
HOTKEY_PREVIOUS_PROFILE = 42;
HOTKEY_SAVE_CONFIG = 43;
HOTKEY_MENU_NAV_UP = 44;
HOTKEY_MENU_NAV_DOWN = 45;
HOTKEY_MENU_NAV_LEFT = 46;
HOTKEY_MENU_NAV_RIGHT = 47;
HOTKEY_MENU_NAV_SELECT = 48;
HOTKEY_MENU_NAV_BACK = 49;
HOTKEY_MENU_NAV_TOGGLE = 50;
}
// This has to be kept in sync with LEDFormat in NeoPico.hpp
@@ -453,6 +470,26 @@ enum PS4ControllerIDMode
PS4_ID_EMULATION = 1;
};
enum DisplaySaverMode
{
option (nanopb_enumopt).long_names = false;
DISPLAY_SAVER_DISPLAY_OFF = 0;
DISPLAY_SAVER_SNOW = 1;
DISPLAY_SAVER_BOUNCE = 2;
DISPLAY_SAVER_PIPES = 3;
DISPLAY_SAVER_TOAST = 4;
};
enum ButtonLayoutOrientation
{
option (nanopb_enumopt).long_names = false;
BUTTON_ORIENTATION_DEFAULT = 0;
BUTTON_ORIENTATION_SOUTHPAW = 1;
BUTTON_ORIENTATION_SWITCHED = 2;
};
enum GPEventType
{
option (nanopb_enumopt).long_names = false;
@@ -469,4 +506,7 @@ enum GPEventType
GP_EVENT_BUTTON_PROCESSED_DOWN = 9;
GP_EVENT_ANALOG_MOVE = 10;
GP_EVENT_ANALOG_PROCESSED_MOVE = 11;
};
GP_EVENT_STORAGE_SAVE = 12;
GP_EVENT_SYSTEM_REBOOT = 13;
GP_EVENT_MENU_NAVIGATE = 14;
};

View File

@@ -22,7 +22,7 @@ bool DisplayAddon::available() {
if (options.enabled) {
// create the gfx interface
gpDisplay = new GPGFX();
gpOptions = gpDisplay->getAvailableDisplay();
gpOptions = gpDisplay->getAvailableDisplay(GPGFX_DisplayType::DISPLAY_TYPE_NONE);
result = (gpOptions.displayType != GPGFX_DisplayType::DISPLAY_TYPE_NONE);
if (!result) delete gpDisplay;
}
@@ -53,6 +53,16 @@ void DisplayAddon::setup() {
displaySaverTimeout = displaySaverTimer;
configMode = Storage::getInstance().GetConfigMode();
turnOffWhenSuspended = options.turnOffWhenSuspended;
displaySaverMode = options.displaySaverMode;
mapMenuToggle = new GamepadButtonMapping(0);
GpioMappingInfo* pinMappings = Storage::getInstance().getProfilePinMappings();
for (Pin_t pin = 0; pin < (Pin_t)NUM_BANK0_GPIOS; pin++) {
switch (pinMappings[pin].action) {
case GpioAction::MENU_NAVIGATION_TOGGLE: mapMenuToggle->pinMask |= 1 << pin; break;
default: break;
}
}
// set current display mode
if (!configMode) {
@@ -68,6 +78,7 @@ void DisplayAddon::setup() {
updateDisplayScreen();
EventManager::getInstance().registerEventHandler(GP_EVENT_RESTART, GPEVENT_CALLBACK(this->handleSystemRestart(event)));
EventManager::getInstance().registerEventHandler(GP_EVENT_MENU_NAVIGATE, GPEVENT_CALLBACK(this->handleMenuNavigation(event)));
}
bool DisplayAddon::updateDisplayScreen() {
@@ -81,7 +92,7 @@ bool DisplayAddon::updateDisplayScreen() {
delete (SplashScreen*)gpScreen;
break;
case MAIN_MENU:
delete (SplashScreen*)gpScreen;
delete (MainMenuScreen*)gpScreen;
break;
case BUTTONS:
delete (ButtonLayoutScreen*)gpScreen;
@@ -89,6 +100,9 @@ bool DisplayAddon::updateDisplayScreen() {
case PIN_VIEWER:
delete (PinViewerScreen*)gpScreen;
break;
case DISPLAY_SAVER:
delete (DisplaySaverScreen*)gpScreen;
break;
case STATS:
delete (StatsScreen*)gpScreen;
break;
@@ -116,6 +130,9 @@ bool DisplayAddon::updateDisplayScreen() {
case PIN_VIEWER:
gpScreen = new PinViewerScreen(gpDisplay);
break;
case DISPLAY_SAVER:
gpScreen = new DisplaySaverScreen(gpDisplay);
break;
case STATS:
gpScreen = new StatsScreen(gpDisplay);
break;
@@ -153,12 +170,19 @@ bool DisplayAddon::isDisplayPowerOff()
displaySaverTimer = displaySaverTimeout;
setDisplayPower(1);
} else if (!!displaySaverTimeout && displaySaverTimer <= 0) {
setDisplayPower(0);
if (displaySaverMode == DisplaySaverMode::DISPLAY_SAVER_DISPLAY_OFF) {
setDisplayPower(0);
} else {
if (currDisplayMode != DISPLAY_SAVER) {
currDisplayMode = DISPLAY_SAVER;
updateDisplayScreen();
}
}
}
prevMillis = getMillis();
return (!!displaySaverTimeout && displaySaverTimer <= 0);
return ((!!displaySaverTimeout && displaySaverTimer <= 0) && (displaySaverMode == DisplaySaverMode::DISPLAY_SAVER_DISPLAY_OFF));
}
void DisplayAddon::setDisplayPower(uint8_t status)
@@ -179,6 +203,15 @@ void DisplayAddon::process() {
int8_t screenReturn = gpScreen->update();
gpScreen->draw();
if (!configMode && screenReturn < 0) {
Mask_t values = Storage::getInstance().GetGamepad()->debouncedGpio;
if (values & mapMenuToggle->pinMask) {
if (currDisplayMode != DisplayMode::MAIN_MENU) {
screenReturn = DisplayMode::MAIN_MENU;
}
}
}
// -1 = we do not change state
if (screenReturn >= 0) {
// Screen wants to change to something else
@@ -199,4 +232,20 @@ void DisplayAddon::handleSystemRestart(GPEvent* e) {
currDisplayMode = DisplayMode::RESTART;
bootMode = (uint32_t)((GPRestartEvent*)e)->bootMode;
updateDisplayScreen();
}
}
void DisplayAddon::handleMenuNavigation(GPEvent* e) {
if (currDisplayMode != MAIN_MENU) {
if (((GPMenuNavigateEvent*)e)->menuAction == GpioAction::MENU_NAVIGATION_TOGGLE) {
currDisplayMode = MAIN_MENU;
updateDisplayScreen();
}
} else {
if (((GPMenuNavigateEvent*)e)->menuAction != GpioAction::MENU_NAVIGATION_TOGGLE) {
((MainMenuScreen*)gpScreen)->updateMenuNavigation(((GPMenuNavigateEvent*)e)->menuAction);
} else {
currDisplayMode = BUTTONS;
updateDisplayScreen();
}
}
}

View File

@@ -28,6 +28,9 @@ void FocusModeAddon::setup() {
void FocusModeAddon::process() {
Gamepad * gamepad = Storage::getInstance().GetGamepad();
Mask_t values = Storage::getInstance().GetGamepad()->debouncedGpio;
if (!Storage::getInstance().getAddonOptions().focusModeOptions.enabled) return;
if (values & mapFocusMode->pinMask) {
if (buttonLockMask & GAMEPAD_MASK_DU) {
gamepad->state.dpad &= ~GAMEPAD_MASK_UP;

View File

@@ -134,6 +134,8 @@ void TurboInput::process()
uint16_t buttonsPressed = gamepad->state.buttons & TURBO_BUTTON_MASK;
uint8_t dpadPressed = gamepad->state.dpad & GAMEPAD_MASK_DPAD;
if (!options.enabled) return;
// Check for TURBO pin enabled
if (gamepad->debouncedGpio & turboPinMask) {
if (buttonsPressed && (lastPressed != buttonsPressed)) {

View File

@@ -413,6 +413,16 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config)
INIT_UNSET_PROPERTY(config.displayOptions, buttonLayout, BUTTON_LAYOUT);
INIT_UNSET_PROPERTY(config.displayOptions, buttonLayoutRight, BUTTON_LAYOUT_RIGHT);
INIT_UNSET_PROPERTY(config.displayOptions, turnOffWhenSuspended, DISPLAY_TURN_OFF_WHEN_SUSPENDED);
INIT_UNSET_PROPERTY(config.displayOptions, inputMode, 1);
INIT_UNSET_PROPERTY(config.displayOptions, turboMode, 1);
INIT_UNSET_PROPERTY(config.displayOptions, dpadMode, 1);
INIT_UNSET_PROPERTY(config.displayOptions, socdMode, 1);
INIT_UNSET_PROPERTY(config.displayOptions, macroMode, 1);
INIT_UNSET_PROPERTY(config.displayOptions, profileMode, 0);
INIT_UNSET_PROPERTY(config.displayOptions, inputHistoryEnabled, !!INPUT_HISTORY_ENABLED);
INIT_UNSET_PROPERTY(config.displayOptions, inputHistoryLength, INPUT_HISTORY_LENGTH);
INIT_UNSET_PROPERTY(config.displayOptions, inputHistoryCol, INPUT_HISTORY_COL);
INIT_UNSET_PROPERTY(config.displayOptions, inputHistoryRow, INPUT_HISTORY_ROW);
ButtonLayoutParamsLeft& paramsLeft = config.displayOptions.buttonLayoutCustomOptions.paramsLeft;
INIT_UNSET_PROPERTY(paramsLeft, layout, BUTTON_LAYOUT);
@@ -437,6 +447,8 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config)
INIT_UNSET_PROPERTY(config.displayOptions, flip, DISPLAY_FLIP);
INIT_UNSET_PROPERTY(config.displayOptions, invert, !!DISPLAY_INVERT);
INIT_UNSET_PROPERTY(config.displayOptions, displaySaverTimeout, DISPLAY_SAVER_TIMEOUT);
INIT_UNSET_PROPERTY(config.displayOptions, displaySaverMode, DISPLAY_SAVER_MODE);
INIT_UNSET_PROPERTY(config.displayOptions, buttonLayoutOrientation, DISPLAY_LAYOUT_ORIENTATION);
// peripheralOptions
PeripheralOptions& peripheralOptions = config.peripheralOptions;
@@ -679,12 +691,6 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config)
INIT_UNSET_PROPERTY(config.addonOptions.buzzerOptions, volume, BUZZER_VOLUME);
INIT_UNSET_PROPERTY(config.addonOptions.buzzerOptions, enablePin, BUZZER_ENABLE_PIN);
// addonOptions.inputHistoryOptions
INIT_UNSET_PROPERTY(config.addonOptions.inputHistoryOptions, enabled, !!INPUT_HISTORY_ENABLED);
INIT_UNSET_PROPERTY(config.addonOptions.inputHistoryOptions, length, INPUT_HISTORY_LENGTH);
INIT_UNSET_PROPERTY(config.addonOptions.inputHistoryOptions, col, INPUT_HISTORY_COL);
INIT_UNSET_PROPERTY(config.addonOptions.inputHistoryOptions, row, INPUT_HISTORY_ROW);
// addonOptions.playerNumberOptions
INIT_UNSET_PROPERTY(config.addonOptions.playerNumberOptions, enabled, !!PLAYERNUM_ADDON_ENABLED);
INIT_UNSET_PROPERTY(config.addonOptions.playerNumberOptions, number, PLAYER_NUMBER);

View File

@@ -450,7 +450,19 @@ std::string setDisplayOptions(DisplayOptions& displayOptions)
readDoc(displayOptions.splashChoice, doc, "splashChoice");
readDoc(displayOptions.splashDuration, doc, "splashDuration");
readDoc(displayOptions.displaySaverTimeout, doc, "displaySaverTimeout");
readDoc(displayOptions.displaySaverMode, doc, "displaySaverMode");
readDoc(displayOptions.buttonLayoutOrientation, doc, "buttonLayoutOrientation");
readDoc(displayOptions.turnOffWhenSuspended, doc, "turnOffWhenSuspended");
readDoc(displayOptions.inputMode, doc, "inputMode");
readDoc(displayOptions.turboMode, doc, "turboMode");
readDoc(displayOptions.dpadMode, doc, "dpadMode");
readDoc(displayOptions.socdMode, doc, "socdMode");
readDoc(displayOptions.macroMode, doc, "macroMode");
readDoc(displayOptions.profileMode, doc, "profileMode");
readDoc(displayOptions.inputHistoryEnabled, doc, "inputHistoryEnabled");
readDoc(displayOptions.inputHistoryLength, doc, "inputHistoryLength");
readDoc(displayOptions.inputHistoryCol, doc, "inputHistoryCol");
readDoc(displayOptions.inputHistoryRow, doc, "inputHistoryRow");
readDoc(displayOptions.buttonLayoutCustomOptions.paramsLeft.layout, doc, "buttonLayoutCustomOptions", "params", "layout");
readDoc(displayOptions.buttonLayoutCustomOptions.paramsLeft.common.startX, doc, "buttonLayoutCustomOptions", "params", "startX");
@@ -492,7 +504,19 @@ std::string getDisplayOptions() // Manually set Document Attributes for the disp
writeDoc(doc, "splashChoice", displayOptions.splashChoice);
writeDoc(doc, "splashDuration", displayOptions.splashDuration);
writeDoc(doc, "displaySaverTimeout", displayOptions.displaySaverTimeout);
writeDoc(doc, "displaySaverMode", displayOptions.displaySaverMode);
writeDoc(doc, "buttonLayoutOrientation", displayOptions.buttonLayoutOrientation);
writeDoc(doc, "turnOffWhenSuspended", displayOptions.turnOffWhenSuspended);
writeDoc(doc, "inputMode", displayOptions.inputMode);
writeDoc(doc, "turboMode", displayOptions.turboMode);
writeDoc(doc, "dpadMode", displayOptions.dpadMode);
writeDoc(doc, "socdMode", displayOptions.socdMode);
writeDoc(doc, "macroMode", displayOptions.macroMode);
writeDoc(doc, "profileMode", displayOptions.profileMode);
writeDoc(doc, "inputHistoryEnabled", displayOptions.inputHistoryEnabled);
writeDoc(doc, "inputHistoryLength", displayOptions.inputHistoryLength);
writeDoc(doc, "inputHistoryCol", displayOptions.inputHistoryCol);
writeDoc(doc, "inputHistoryRow", displayOptions.inputHistoryRow);
writeDoc(doc, "buttonLayoutCustomOptions", "params", "layout", displayOptions.buttonLayoutCustomOptions.paramsLeft.layout);
writeDoc(doc, "buttonLayoutCustomOptions", "params", "startX", displayOptions.buttonLayoutCustomOptions.paramsLeft.common.startX);
@@ -1589,12 +1613,6 @@ std::string setAddonOptions()
docToPin(snesOptions.latchPin, doc, "snesPadLatchPin");
docToPin(snesOptions.dataPin, doc, "snesPadDataPin");
InputHistoryOptions& inputHistoryOptions = Storage::getInstance().getAddonOptions().inputHistoryOptions;
docToValue(inputHistoryOptions.length, doc, "inputHistoryLength");
docToValue(inputHistoryOptions.enabled, doc, "InputHistoryAddonEnabled");
docToValue(inputHistoryOptions.col, doc, "inputHistoryCol");
docToValue(inputHistoryOptions.row, doc, "inputHistoryRow");
KeyboardHostOptions& keyboardHostOptions = Storage::getInstance().getAddonOptions().keyboardHostOptions;
docToValue(keyboardHostOptions.enabled, doc, "KeyboardHostAddonEnabled");
docToValue(keyboardHostOptions.mapping.keyDpadUp, doc, "keyboardHostMap", "Up");
@@ -2005,12 +2023,6 @@ std::string getAddonOptions()
writeDoc(doc, "snesPadDataPin", cleanPin(snesOptions.dataPin));
writeDoc(doc, "SNESpadAddonEnabled", snesOptions.enabled);
const InputHistoryOptions& inputHistoryOptions = Storage::getInstance().getAddonOptions().inputHistoryOptions;
writeDoc(doc, "inputHistoryLength", inputHistoryOptions.length);
writeDoc(doc, "InputHistoryAddonEnabled", inputHistoryOptions.enabled);
writeDoc(doc, "inputHistoryCol", inputHistoryOptions.col);
writeDoc(doc, "inputHistoryRow", inputHistoryOptions.row);
const KeyboardHostOptions& keyboardHostOptions = Storage::getInstance().getAddonOptions().keyboardHostOptions;
writeDoc(doc, "KeyboardHostAddonEnabled", keyboardHostOptions.enabled);
writeDoc(doc, "keyboardHostMap", "Up", keyboardHostOptions.mapping.keyDpadUp);

View File

@@ -24,7 +24,6 @@ GPGFX::GPGFX() {
void GPGFX::init(GPGFX_DisplayTypeOptions options) {
switch (options.displayType) {
case GPGFX_DisplayType::DISPLAY_TYPE_SSD1306:
//this->displayDriver = new GPGFX_OBD_SSD1306();
this->displayDriver = new GPGFX_TinySSD1306();
break;
default:
@@ -37,38 +36,53 @@ void GPGFX::init(GPGFX_DisplayTypeOptions options) {
}
}
GPGFX_DisplayTypeOptions GPGFX::getAvailableDisplay() {
GPGFX_DisplayBase* driver = nullptr;
GPGFX_DisplayTypeOptions GPGFX::getAvailableDisplay(GPGFX_DisplayType displayType) {
GPGFX_DisplayTypeOptions display;
display.displayType = GPGFX_DisplayType::DISPLAY_TYPE_NONE;
display.displayType = displayType;
for (uint16_t i = GPGFX_DisplayType::DISPLAY_TYPE_NONE; i < GPGFX_DisplayType::DISPLAY_TYPE_COUNT; i++) {
if (i == GPGFX_DisplayType::DISPLAY_TYPE_SSD1306) {
driver = new GPGFX_TinySSD1306();
} else {
driver = nullptr;
if (display.displayType == GPGFX_DisplayType::DISPLAY_TYPE_NONE) {
// autoscan for device
for (uint16_t i = GPGFX_DisplayType::DISPLAY_TYPE_NONE; i < GPGFX_DisplayType::DISPLAY_TYPE_COUNT; i++) {
if (detectDisplay(&display, (GPGFX_DisplayType)i)) break;
}
if ((driver != nullptr) && (display.displayType == GPGFX_DisplayType::DISPLAY_TYPE_NONE)) {
if (driver->isI2C()) {
PeripheralI2CScanResult result = PeripheralManager::getInstance().scanForI2CDevice(driver->getDeviceAddresses());
if (result.address > -1) {
display.displayType = (GPGFX_DisplayType)i;
display.address = result.address;
display.i2c = PeripheralManager::getInstance().getI2C(result.block);
display.i2c->setExclusiveUse(result.address);
return display;
}
}
if (driver->isSPI()) {
// NYI: check if SPI display exists
}
delete driver;
} else {
if (!detectDisplay(&display, display.displayType)) {
display.displayType = GPGFX_DisplayType::DISPLAY_TYPE_NONE;
}
}
return display;
}
bool GPGFX::detectDisplay(GPGFX_DisplayTypeOptions* display, GPGFX_DisplayType displayType) {
GPGFX_DisplayBase* driver = nullptr;
if (displayType == GPGFX_DisplayType::DISPLAY_TYPE_SSD1306) {
driver = new GPGFX_TinySSD1306();
} else {
driver = nullptr;
}
if (driver != nullptr) {
if (driver->isI2C()) {
PeripheralI2CScanResult result = PeripheralManager::getInstance().scanForI2CDevice(driver->getDeviceAddresses());
if (result.address > -1) {
display->displayType = displayType;
display->address = result.address;
display->i2c = PeripheralManager::getInstance().getI2C(result.block);
display->i2c->setExclusiveUse(result.address);
return true;
}
}
if (driver->isSPI()) {
// NYI: check if SPI display exists
}
delete driver;
}
return false;
}
void GPGFX::clearScreen() {
this->displayDriver->clear();
}
@@ -77,6 +91,10 @@ void GPGFX::render() {
this->displayDriver->drawBuffer(NULL);
}
uint32_t GPGFX::getPixel(uint16_t x, uint16_t y) {
return this->displayDriver->getPixel(x, y);
}
void GPGFX::drawPixel(uint16_t x, uint16_t y, uint32_t color) {
this->displayDriver->drawPixel(x, y, color);
}
@@ -105,6 +123,6 @@ void GPGFX::drawPolygon(uint16_t x, uint16_t y, uint16_t radius, uint16_t sides,
this->displayDriver->drawPolygon(x, y, radius, sides, color, filled, rotation);
}
void GPGFX::drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority) {
this->displayDriver->drawSprite(spriteData, width, height, pitch, x, y, priority);
void GPGFX::drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority, double scale) {
this->displayDriver->drawSprite(spriteData, width, height, pitch, x, y, priority, scale);
}

View File

@@ -93,7 +93,6 @@ void GPButton::draw() {
if (useMask && mapMask != NULL) {
maskedPins = (pinValues & mapMask->pinMask);
for (Pin_t pin = 0; pin < (Pin_t)NUM_BANK0_GPIOS; pin++) {
if ((maskedPins & (1 << pin)) == (1 << pin)) {
setPin = pin;

View File

@@ -43,13 +43,13 @@ void GPLever::draw() {
bool leftState = (this->_leftMask > -1 ? getProcessedGamepad()->pressedButton((uint16_t)this->_leftMask) : getProcessedGamepad()->pressedLeft());
bool downState = (this->_downMask > -1 ? getProcessedGamepad()->pressedButton((uint16_t)this->_downMask) : getProcessedGamepad()->pressedDown());
bool rightState = (this->_rightMask > -1 ? getProcessedGamepad()->pressedButton((uint16_t)this->_rightMask) : getProcessedGamepad()->pressedRight());
if (upState != downState) {
leverY -= upState ? leverRadius : -leverRadius;
if (upState != downState) {
leverY -= upState ? leverRadius : -leverRadius;
}
if (leftState != rightState) {
leverX -= leftState ? leverRadius : -leverRadius;
}
} else {
if (leftState != rightState) {
leverX -= leftState ? leverRadius : -leverRadius;
}
} else {
// analog
uint16_t analogX = map((this->_inputType == DPAD_MODE_LEFT_ANALOG ? getProcessedGamepad()->state.lx : getProcessedGamepad()->state.rx), 0, 0xFFFF, 0, 100);
uint16_t analogY = map((this->_inputType == DPAD_MODE_LEFT_ANALOG ? getProcessedGamepad()->state.ly : getProcessedGamepad()->state.ry), 0, 0xFFFF, 0, 100);

View File

@@ -0,0 +1,45 @@
#include "GPMenu.h"
#include <string>
void GPMenu::draw() {
if (this->getVisibility()) {
uint16_t baseX = this->x;
uint16_t baseY = this->y;
uint16_t menuWidth = this->menuSizeX * 6;
uint16_t menuHeight = this->menuSizeY * 8;
uint16_t dataSize = this->getDataSize();
uint16_t totalPages = (dataSize + this->menuSizeY - 1) / this->menuSizeY;
uint16_t itemPage = (this->menuIndex / this->menuSizeY);
int16_t currPageItems = (dataSize - (itemPage * this->menuSizeY));
if (currPageItems > this->menuSizeY) {
currPageItems = this->menuSizeY;
} else if (currPageItems <= 0) {
currPageItems = 0;
}
getRenderer()->drawText((21-this->menuTitle.length()) / 2, 0, this->menuTitle.c_str());
std::string pageDisplay = "";
pageDisplay += "Page: " + std::to_string(itemPage+1) + "/" + std::to_string(totalPages);
getRenderer()->drawText(11, 7, pageDisplay.c_str());
if (this->menuEntryData->size() > 0) {
for (uint8_t menuLine = 0; menuLine < currPageItems; menuLine++) {
uint8_t pageLine = (this->menuSizeY * itemPage) + menuLine;
int32_t lineValue = this->menuEntryData->at(pageLine).optionValue;
bool showCurrentOption = false;
if (lineValue != -1) {
showCurrentOption = (this->menuEntryData->at(pageLine).currentValue() == this->menuEntryData->at(pageLine).optionValue);
}
getRenderer()->drawText(2, 2+menuLine, this->menuEntryData->at(pageLine).label + (showCurrentOption ? " *" : ""));
}
}
// draw cursor
getRenderer()->drawText(1, 2+(this->menuIndex % this->menuSizeY), CHAR_RIGHT);
}
}

View File

@@ -6,11 +6,10 @@
#include "drivers/xinput/XInputDriver.h"
void ButtonLayoutScreen::init() {
const InputHistoryOptions& inputHistoryOptions = Storage::getInstance().getAddonOptions().inputHistoryOptions;
isInputHistoryEnabled = inputHistoryOptions.enabled;
inputHistoryX = inputHistoryOptions.row;
inputHistoryY = inputHistoryOptions.col;
inputHistoryLength = inputHistoryOptions.length;
isInputHistoryEnabled = Storage::getInstance().getDisplayOptions().inputHistoryEnabled;
inputHistoryX = Storage::getInstance().getDisplayOptions().inputHistoryRow;
inputHistoryY = Storage::getInstance().getDisplayOptions().inputHistoryCol;
inputHistoryLength = Storage::getInstance().getDisplayOptions().inputHistoryLength;
bannerDelayStart = getMillis();
gamepad = Storage::getInstance().GetGamepad();
inputMode = DriverManager::getInstance().getInputMode();
@@ -44,6 +43,7 @@ void ButtonLayoutScreen::init() {
prevLayoutRight = Storage::getInstance().getDisplayOptions().buttonLayoutRight;
prevLeftOptions = Storage::getInstance().getDisplayOptions().buttonLayoutCustomOptions.paramsLeft;
prevRightOptions = Storage::getInstance().getDisplayOptions().buttonLayoutCustomOptions.paramsRight;
prevOrientation = Storage::getInstance().getDisplayOptions().buttonLayoutOrientation;
// we cannot look at macro options enabled, pull the pins
@@ -68,6 +68,14 @@ void ButtonLayoutScreen::init() {
}
}
// determine which fields will be displayed on the status bar
showInputMode = Storage::getInstance().getDisplayOptions().inputMode;
showTurboMode = Storage::getInstance().getDisplayOptions().turboMode;
showDpadMode = Storage::getInstance().getDisplayOptions().dpadMode;
showSocdMode = Storage::getInstance().getDisplayOptions().socdMode;
showMacroMode = Storage::getInstance().getDisplayOptions().macroMode;
showProfileMode = Storage::getInstance().getDisplayOptions().profileMode;
getRenderer()->clearScreen();
}
@@ -83,8 +91,9 @@ int8_t ButtonLayoutScreen::update() {
if (configMode) {
uint8_t layoutLeft = Storage::getInstance().getDisplayOptions().buttonLayout;
uint8_t layoutRight = Storage::getInstance().getDisplayOptions().buttonLayoutRight;
bool inputHistoryEnabled = Storage::getInstance().getAddonOptions().inputHistoryOptions.enabled;
if ((prevLayoutLeft != layoutLeft) || (prevLayoutRight != layoutRight) || (isInputHistoryEnabled != inputHistoryEnabled) || compareCustomLayouts()) {
uint8_t buttonLayoutOrientation = Storage::getInstance().getDisplayOptions().buttonLayoutOrientation;
bool inputHistoryEnabled = Storage::getInstance().getDisplayOptions().inputHistoryEnabled;
if ((prevLayoutLeft != layoutLeft) || (prevLayoutRight != layoutRight) || (isInputHistoryEnabled != inputHistoryEnabled) || compareCustomLayouts() || (prevOrientation != buttonLayoutOrientation)) {
shutdown();
init();
}
@@ -143,80 +152,102 @@ void ButtonLayoutScreen::generateHeader() {
}
}
// Display standard header
switch (inputMode)
{
case INPUT_MODE_PS3: statusBar += "PS3"; break;
case INPUT_MODE_GENERIC: statusBar += "USBHID"; break;
case INPUT_MODE_SWITCH: statusBar += "SWITCH"; break;
case INPUT_MODE_MDMINI: statusBar += "GEN/MD"; break;
case INPUT_MODE_NEOGEO: statusBar += "NGMINI"; break;
case INPUT_MODE_PCEMINI: statusBar += "PCE/TG"; break;
case INPUT_MODE_EGRET: statusBar += "EGRET"; break;
case INPUT_MODE_ASTRO: statusBar += "ASTRO"; break;
case INPUT_MODE_PSCLASSIC: statusBar += "PSC"; break;
case INPUT_MODE_XBOXORIGINAL: statusBar += "OGXBOX"; break;
case INPUT_MODE_PS4:
statusBar += "PS4";
if(((PS4Driver*)DriverManager::getInstance().getDriver())->getAuthSent() == true )
statusBar += ":AS";
else
statusBar += " ";
break;
case INPUT_MODE_PS5:
statusBar += "PS5";
if(((PS4Driver*)DriverManager::getInstance().getDriver())->getAuthSent() == true )
statusBar += ":AS";
else
statusBar += " ";
break;
case INPUT_MODE_XBONE:
statusBar += "XBON";
if(((XBOneDriver*)DriverManager::getInstance().getDriver())->getAuthSent() == true )
statusBar += "E";
else
statusBar += "*";
break;
case INPUT_MODE_XINPUT:
statusBar += "X";
if(((XInputDriver*)DriverManager::getInstance().getDriver())->getAuthEnabled() == true )
statusBar += "B360";
else
statusBar += "INPUT";
break;
case INPUT_MODE_KEYBOARD: statusBar += "HID-KB"; break;
case INPUT_MODE_CONFIG: statusBar += "CONFIG"; break;
}
if (showInputMode) {
// Display standard header
switch (inputMode)
{
case INPUT_MODE_PS3: statusBar += "PS3"; break;
case INPUT_MODE_GENERIC: statusBar += "USBHID"; break;
case INPUT_MODE_SWITCH: statusBar += "SWITCH"; break;
case INPUT_MODE_MDMINI: statusBar += "GEN/MD"; break;
case INPUT_MODE_NEOGEO: statusBar += "NGMINI"; break;
case INPUT_MODE_PCEMINI: statusBar += "PCE/TG"; break;
case INPUT_MODE_EGRET: statusBar += "EGRET"; break;
case INPUT_MODE_ASTRO: statusBar += "ASTRO"; break;
case INPUT_MODE_PSCLASSIC: statusBar += "PSC"; break;
case INPUT_MODE_XBOXORIGINAL: statusBar += "OGXBOX"; break;
case INPUT_MODE_PS4:
statusBar += "PS4";
if(((PS4Driver*)DriverManager::getInstance().getDriver())->getAuthSent() == true )
statusBar += ":AS";
else
statusBar += " ";
break;
case INPUT_MODE_PS5:
statusBar += "PS5";
if(((PS4Driver*)DriverManager::getInstance().getDriver())->getAuthSent() == true )
statusBar += ":AS";
else
statusBar += " ";
break;
case INPUT_MODE_XBONE:
statusBar += "XBON";
if(((XBOneDriver*)DriverManager::getInstance().getDriver())->getAuthSent() == true )
statusBar += "E";
else
statusBar += "*";
break;
case INPUT_MODE_XINPUT:
statusBar += "X";
if(((XInputDriver*)DriverManager::getInstance().getDriver())->getAuthEnabled() == true )
statusBar += "B360";
else
statusBar += "INPUT";
break;
case INPUT_MODE_KEYBOARD: statusBar += "HID-KB"; break;
case INPUT_MODE_CONFIG: statusBar += "CONFIG"; break;
}
}
const TurboOptions& turboOptions = storage.getAddonOptions().turboOptions;
if ( turboOptions.enabled ) {
statusBar += " T";
if ( turboOptions.shotCount < 10 ) // padding
statusBar += "0";
statusBar += std::to_string(turboOptions.shotCount);
} else {
statusBar += " "; // no turbo, don't show Txx setting
}
if (showTurboMode) {
const TurboOptions& turboOptions = storage.getAddonOptions().turboOptions;
if ( turboOptions.enabled ) {
statusBar += " T";
if ( turboOptions.shotCount < 10 ) // padding
statusBar += "0";
statusBar += std::to_string(turboOptions.shotCount);
} else {
statusBar += " "; // no turbo, don't show Txx setting
}
}
const GamepadOptions & options = gamepad->getOptions();
switch (gamepad->getActiveDpadMode())
{
case DPAD_MODE_DIGITAL: statusBar += " D"; break;
case DPAD_MODE_LEFT_ANALOG: statusBar += " L"; break;
case DPAD_MODE_RIGHT_ANALOG: statusBar += " R"; break;
}
if (showDpadMode) {
switch (gamepad->getActiveDpadMode())
{
case DPAD_MODE_DIGITAL: statusBar += " D"; break;
case DPAD_MODE_LEFT_ANALOG: statusBar += " L"; break;
case DPAD_MODE_RIGHT_ANALOG: statusBar += " R"; break;
}
}
switch (Gamepad::resolveSOCDMode(gamepad->getOptions()))
{
case SOCD_MODE_NEUTRAL: statusBar += " SOCD-N"; break;
case SOCD_MODE_UP_PRIORITY: statusBar += " SOCD-U"; break;
case SOCD_MODE_SECOND_INPUT_PRIORITY: statusBar += " SOCD-L"; break;
case SOCD_MODE_FIRST_INPUT_PRIORITY: statusBar += " SOCD-F"; break;
case SOCD_MODE_BYPASS: statusBar += " SOCD-X"; break;
}
if (macroEnabled)
statusBar += " M";
if (showSocdMode) {
switch (Gamepad::resolveSOCDMode(gamepad->getOptions()))
{
case SOCD_MODE_NEUTRAL: statusBar += " SOCD-N"; break;
case SOCD_MODE_UP_PRIORITY: statusBar += " SOCD-U"; break;
case SOCD_MODE_SECOND_INPUT_PRIORITY: statusBar += " SOCD-L"; break;
case SOCD_MODE_FIRST_INPUT_PRIORITY: statusBar += " SOCD-F"; break;
case SOCD_MODE_BYPASS: statusBar += " SOCD-X"; break;
}
}
if (showMacroMode && macroEnabled) statusBar += " M";
if (showProfileMode) {
statusBar += " Pr:";
std::string profile;
profile.assign(storage.currentProfileLabel(), strlen(storage.currentProfileLabel()));
if (profile.empty()) {
statusBar += std::to_string(getGamepad()->getOptions().profileNumber);
} else {
statusBar += profile;
}
}
trim(statusBar);
}
void ButtonLayoutScreen::drawScreen() {
@@ -514,3 +545,8 @@ void ButtonLayoutScreen::handleUSB(GPEvent* e) {
}
bannerDisplay = true;
}
void ButtonLayoutScreen::trim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::not1(std::ptr_fun<int, int>(std::isspace))));
}

View File

@@ -0,0 +1,197 @@
#include "DisplaySaverScreen.h"
#include "pico/stdlib.h"
#include "version.h"
void DisplaySaverScreen::init() {
const DisplayOptions& options = Storage::getInstance().getDisplayOptions();
displaySaverMode = options.displaySaverMode;
getRenderer()->clearScreen();
switch (displaySaverMode) {
case DisplaySaverMode::DISPLAY_SAVER_SNOW:
initSnowScene();
break;
case DisplaySaverMode::DISPLAY_SAVER_BOUNCE:
break;
case DisplaySaverMode::DISPLAY_SAVER_PIPES:
break;
case DisplaySaverMode::DISPLAY_SAVER_TOAST:
initToasters();
break;
}
}
void DisplaySaverScreen::shutdown() {
clearElements();
}
void DisplaySaverScreen::drawScreen() {
switch (displaySaverMode) {
case DisplaySaverMode::DISPLAY_SAVER_SNOW:
drawSnowScene();
break;
case DisplaySaverMode::DISPLAY_SAVER_BOUNCE:
drawBounceScene();
break;
case DisplaySaverMode::DISPLAY_SAVER_PIPES:
drawPipeScene();
break;
case DisplaySaverMode::DISPLAY_SAVER_TOAST:
drawToasterScene();
break;
}
}
int8_t DisplaySaverScreen::update() {
if (!Storage::getInstance().GetConfigMode()) {
uint16_t buttonState = getGamepad()->state.buttons;
if (prevButtonState && !buttonState) {
if (prevButtonState != 0) {
prevButtonState = 0;
return DisplayMode::BUTTONS;
}
}
prevButtonState = buttonState;
}
return -1; // -1 means no change in screen state
}
void DisplaySaverScreen::initSnowScene() {
for (uint8_t x = 0; x < SCREEN_WIDTH; ++x) {
for (uint8_t y = 0; y < SCREEN_HEIGHT; ++y) {
snowflakeSpeeds[x][y] = 0;
snowflakeDrift[x][y] = 0;
getRenderer()->drawPixel(x, y, 0);
}
}
}
void DisplaySaverScreen::drawSnowScene() {
for (int8_t y = SCREEN_HEIGHT - 1; y >= 0; --y) {
for (uint8_t x = 0; x < SCREEN_WIDTH; ++x) {
if (snowflakeSpeeds[x][y] > 0) {
uint8_t speed = snowflakeSpeeds[x][y];
uint8_t newY = y + speed;
int8_t drift = snowflakeDrift[x][y];
int8_t newX = x + drift;
if (newX < 0) newX = 0;
if (newX >= SCREEN_WIDTH) newX = SCREEN_WIDTH - 1;
if (newY >= SCREEN_HEIGHT) {
getRenderer()->drawPixel(x, y, 0);
snowflakeSpeeds[x][y] = 0;
snowflakeDrift[x][y] = 0;
} else {
getRenderer()->drawPixel(x, y, 0);
getRenderer()->drawPixel(newX, newY, 1);
snowflakeSpeeds[newX][newY] = speed;
snowflakeDrift[newX][newY] = drift;
snowflakeSpeeds[x][y] = 0;
snowflakeDrift[x][y] = 0;
}
}
}
}
for (uint8_t x = 0; x < SCREEN_WIDTH; ++x) {
if (rand() % 10 == 0) {
getRenderer()->drawPixel(x, 0, 1);
snowflakeSpeeds[x][0] = (rand() % 3) + 1;
snowflakeDrift[x][0] = (rand() % 3) - 1;
}
}
}
void DisplaySaverScreen::drawBounceScene() {
uint16_t scaledWidth = static_cast<uint16_t>(bounceSpriteWidth * bounceScale);
uint16_t scaledHeight = static_cast<uint16_t>(bounceSpriteHeight * bounceScale);
bounceSpriteX += bounceSpriteVelocityX;
bounceSpriteY += bounceSpriteVelocityY;
if (bounceSpriteX <= 0 || bounceSpriteX + scaledWidth >= SCREEN_WIDTH) bounceSpriteVelocityX = -bounceSpriteVelocityX;
if (bounceSpriteY <= 0 || bounceSpriteY + scaledHeight >= SCREEN_HEIGHT) bounceSpriteVelocityY = -bounceSpriteVelocityY;
getRenderer()->drawSprite((uint8_t *)bootLogoBottom, bounceSpriteWidth, bounceSpriteHeight, 0, bounceSpriteX, bounceSpriteY, 0, bounceScale);
}
void DisplaySaverScreen::drawPipeScene() {
const uint8_t PIPE_WIDTH = 4;
const uint8_t PIPE_COLOR = 1;
uint8_t currentX = 0;
uint8_t currentY = 0;
while (currentY < SCREEN_HEIGHT) {
bool connectRight = rand() % 2;
bool connectDown = rand() % 2;
if (connectRight && currentX + PIPE_WIDTH < SCREEN_WIDTH) {
for (uint8_t i = 0; i < PIPE_WIDTH; ++i) {
getRenderer()->drawPixel(currentX + i, currentY, PIPE_COLOR);
}
}
if (connectDown && currentY + PIPE_WIDTH < SCREEN_HEIGHT) {
for (uint8_t i = 0; i < PIPE_WIDTH; ++i) {
getRenderer()->drawPixel(currentX, currentY + i, PIPE_COLOR);
}
}
getRenderer()->drawPixel(currentX, currentY, PIPE_COLOR);
currentX += PIPE_WIDTH;
if (currentX >= SCREEN_WIDTH) {
currentX = 0;
currentY += PIPE_WIDTH;
}
for (volatile uint32_t delay = 0; delay < 10000; ++delay) {
// Do nothing, just burn some CPU cycles
}
}
}
void DisplaySaverScreen::initToasters() {
for (uint16_t i = 0; i < numberOfToasters; ++i) {
double scale = (static_cast<double>(rand()) / RAND_MAX);
int16_t dx = (-1 - rand() % 3);
int16_t dy = (1 + rand() % 3);
toasters.push_back({
(uint8_t *)bootLogoTop,
toasterSpriteWidth,
toasterSpriteHeight,
scale,
static_cast<int16_t>(SCREEN_WIDTH - toasterSpriteWidth * scale),
static_cast<int16_t>(rand() % (SCREEN_HEIGHT - static_cast<int16_t>(toasterSpriteHeight * scale))),
static_cast<int16_t>(dx),
static_cast<int16_t>(dy)
});
}
}
void DisplaySaverScreen::drawToasterScene() {
for (uint16_t i = 0; i < toasters.size(); ++i) {
ToastParams& sprite = toasters[i];
getRenderer()->drawSprite(sprite.image, sprite.width, sprite.height, 0, sprite.x, sprite.y, 0, sprite.scale);
sprite.x += sprite.dx;
sprite.y += sprite.dy;
if (sprite.x + sprite.width * sprite.scale < 0) {
sprite.x = SCREEN_WIDTH;
sprite.y = rand() % (SCREEN_HEIGHT - static_cast<int16_t>(sprite.height * sprite.scale));
}
if (sprite.y > SCREEN_HEIGHT) {
sprite.y = 0;
}
}
}

View File

@@ -1,55 +1,114 @@
#include "MainMenuScreen.h"
#include "hardware/watchdog.h"
#include "system.h"
extern uint32_t getMillis();
void MainMenuScreen::init() {
getRenderer()->clearScreen();
currentMenu = &mainMenu;
previousMenu = nullptr;
exitToScreen = -1;
gpMenu = new GPMenu();
gpMenu->setRenderer(getRenderer());
gpMenu->setPosition(8, 16);
gpMenu->setStrokeColor(1);
gpMenu->setFillColor(1);
gpMenu->setMenuSize(18, 4);
gpMenu->setViewport(this->getViewport());
gpMenu->setShape(GPShape_Type::GP_SHAPE_SQUARE);
gpMenu->setMenuData(currentMenu);
gpMenu->setMenuTitle(MAIN_MENU_NAME);
addElement(gpMenu);
mapMenuUp = new GamepadButtonMapping(0);
mapMenuDown = new GamepadButtonMapping(0);
mapMenuLeft = new GamepadButtonMapping(0);
mapMenuRight = new GamepadButtonMapping(0);
mapMenuSelect = new GamepadButtonMapping(0);
mapMenuBack = new GamepadButtonMapping(0);
mapMenuToggle = new GamepadButtonMapping(0);
// populate the profiles menu
uint8_t profileCount = (sizeof(Storage::getInstance().getProfileOptions().gpioMappingsSets)/sizeof(GpioMappings))+1;
for (uint8_t profileCtr = 0; profileCtr < profileCount; profileCtr++) {
std::string menuLabel = "";
if (profileCtr == 0) {
menuLabel = Storage::getInstance().getGpioMappings().profileLabel;
} else {
menuLabel = Storage::getInstance().getProfileOptions().gpioMappingsSets[profileCtr-1].profileLabel;
}
if (menuLabel.empty()) {
menuLabel = "Profile #" + std::to_string(profileCtr);
}
MenuEntry menuEntry = {menuLabel, NULL, nullptr, std::bind(&MainMenuScreen::currentProfile, this), std::bind(&MainMenuScreen::selectProfile, this), profileCtr+1};
profilesMenu.push_back(menuEntry);
}
GpioMappingInfo* pinMappings = Storage::getInstance().getProfilePinMappings();
for (Pin_t pin = 0; pin < (Pin_t)NUM_BANK0_GPIOS; pin++) {
switch (pinMappings[pin].action) {
case GpioAction::MENU_NAVIGATION_UP: mapMenuUp->pinMask |= 1 << pin; break;
case GpioAction::MENU_NAVIGATION_DOWN: mapMenuDown->pinMask |= 1 << pin; break;
case GpioAction::MENU_NAVIGATION_LEFT: mapMenuLeft->pinMask |= 1 << pin; break;
case GpioAction::MENU_NAVIGATION_RIGHT: mapMenuRight->pinMask |= 1 << pin; break;
case GpioAction::MENU_NAVIGATION_SELECT: mapMenuSelect->pinMask |= 1 << pin; break;
case GpioAction::MENU_NAVIGATION_BACK: mapMenuBack->pinMask |= 1 << pin; break;
case GpioAction::MENU_NAVIGATION_TOGGLE: mapMenuToggle->pinMask |= 1 << pin; break;
default: break;
}
}
changeRequiresReboot = false;
changeRequiresSave = false;
prevInputMode = Storage::getInstance().GetGamepad()->getOptions().inputMode;
updateInputMode = Storage::getInstance().GetGamepad()->getOptions().inputMode;
prevDpadMode = Storage::getInstance().GetGamepad()->getOptions().dpadMode;
updateDpadMode = Storage::getInstance().GetGamepad()->getOptions().dpadMode;
prevSocdMode = Storage::getInstance().GetGamepad()->getOptions().socdMode;
updateSocdMode = Storage::getInstance().GetGamepad()->getOptions().socdMode;
prevProfile = Storage::getInstance().GetGamepad()->getOptions().profileNumber;
updateProfile = Storage::getInstance().GetGamepad()->getOptions().profileNumber;
prevFocus = Storage::getInstance().getAddonOptions().focusModeOptions.enabled;
updateFocus = Storage::getInstance().getAddonOptions().focusModeOptions.enabled;
prevTurbo = Storage::getInstance().getAddonOptions().turboOptions.enabled;
updateTurbo = Storage::getInstance().getAddonOptions().turboOptions.enabled;
}
void MainMenuScreen::shutdown() {
clearElements();
exitToScreen = -1;
}
void MainMenuScreen::drawScreen() {
getRenderer()->drawText(1, 1, "GPGFX_UI Test Menu");
gpMenu->setVisibility(!screenIsPrompting);
for (size_t i = 0; i < currentMenu->size(); ++i) {
MenuEntry entry = currentMenu->at(i);
if (!screenIsPrompting) {
getRenderer()->drawText(3, 3+i, entry.label);
}
/*
if (!isPressed) {
if (pressedUp()) {
if (menuIndex > 0) {
menuIndex--;
} else {
menuIndex = currentMenu->size()-1;
}
checkDebounce = getMillis();
isPressed = true;
} else if (pressedDown()) {
if (menuIndex < currentMenu->size()-1) {
menuIndex++;
} else {
menuIndex = 0;
}
checkDebounce = getMillis();
isPressed = true;
} else if (pressedB1()) {
currentMenu->at(menuIndex).action();
checkDebounce = getMillis();
isPressed = true;
}
} else {
if (isPressed && ((getMillis() - checkDebounce) > 400)) {
isPressed = false;
}
}
*/
getRenderer()->drawText(1, 1, "Config has changed.");
if (changeRequiresSave && !changeRequiresReboot) {
getRenderer()->drawText(3, 3, "Would you like");
getRenderer()->drawText(6, 4, "to save?");
} else if (changeRequiresSave && changeRequiresReboot) {
getRenderer()->drawText(3, 3, "Would you like");
getRenderer()->drawText(1, 4, "to save & restart?");
} else {
getRenderer()->drawText(1, 3+menuIndex, ">");
}
if (promptChoice) getRenderer()->drawText(5, 6, CHAR_RIGHT);
getRenderer()->drawText(6, 6, "Yes");
if (!promptChoice) getRenderer()->drawText(11, 6, CHAR_RIGHT);
getRenderer()->drawText(12, 6, "No");
}
}
void MainMenuScreen::setMenu(std::vector<MenuEntry>* menu) {
@@ -57,51 +116,284 @@ void MainMenuScreen::setMenu(std::vector<MenuEntry>* menu) {
}
int8_t MainMenuScreen::update() {
Gamepad * gamepad = Storage::getInstance().GetGamepad();
Mask_t values = Storage::getInstance().GetGamepad()->debouncedGpio;
uint16_t buttonState = getGamepad()->state.buttons;
if (prevButtonState && !buttonState) {
switch (prevButtonState) {
case (GAMEPAD_MASK_B1):
if (!isPressed && prevValues != values) {
if (values & mapMenuUp->pinMask) {
updateMenuNavigation(GpioAction::MENU_NAVIGATION_UP);
} else if (values & mapMenuDown->pinMask) {
updateMenuNavigation(GpioAction::MENU_NAVIGATION_DOWN);
} else if (values & mapMenuSelect->pinMask) {
updateMenuNavigation(GpioAction::MENU_NAVIGATION_SELECT);
} else if (values & mapMenuBack->pinMask) {
updateMenuNavigation(GpioAction::MENU_NAVIGATION_BACK);
}
} else {
isPressed = false;
}
prevButtonState = buttonState;
prevValues = values;
if ((exitToScreen != -1) && ((changeRequiresSave) || (changeRequiresReboot))) {
// trying to exit menu but a change requires a save/reboot
exitToScreenBeforePrompt = exitToScreen;
exitToScreen = -1;
screenIsPrompting = true;
}
return exitToScreen;
}
void MainMenuScreen::updateMenuNavigation(GpioAction action) {
bool changeIndex = false;
uint16_t menuSize = gpMenu->getDataSize();
switch (action) {
case GpioAction::MENU_NAVIGATION_UP:
if (!screenIsPrompting) {
if (menuIndex > 0) {
menuIndex--;
} else {
menuIndex = currentMenu->size()-1;
menuIndex = menuSize-1;
}
break;
case (GAMEPAD_MASK_B2):
if (menuIndex < currentMenu->size()-1) {
changeIndex = true;
} else {
promptChoice = !promptChoice;
}
isPressed = true;
break;
case GpioAction::MENU_NAVIGATION_DOWN:
if (!screenIsPrompting) {
if (menuIndex < menuSize-1) {
menuIndex++;
} else {
menuIndex = 0;
}
break;
case (GAMEPAD_MASK_S1):
currentMenu->at(menuIndex).action();
break;
default:
//prevDisplayMode = DisplayMode::CONFIG_INSTRUCTION;
break;
}
changeIndex = true;
} else {
promptChoice = !promptChoice;
}
isPressed = true;
break;
case GpioAction::MENU_NAVIGATION_LEFT:
if (screenIsPrompting) {
promptChoice = !promptChoice;
}
isPressed = true;
break;
case GpioAction::MENU_NAVIGATION_RIGHT:
if (screenIsPrompting) {
promptChoice = !promptChoice;
}
isPressed = true;
break;
case GpioAction::MENU_NAVIGATION_SELECT:
if (!screenIsPrompting) {
if (currentMenu->at(menuIndex).submenu != nullptr) {
previousMenu = currentMenu;
currentMenu = currentMenu->at(menuIndex).submenu;
gpMenu->setMenuData(currentMenu);
gpMenu->setMenuTitle(previousMenu->at(menuIndex).label);
menuIndex = 0;
changeIndex = true;
} else {
currentMenu->at(menuIndex).action();
}
} else {
if (promptChoice) {
saveOptions();
} else {
resetOptions();
exitToScreen = DisplayMode::BUTTONS;
exitToScreenBeforePrompt = DisplayMode::BUTTONS;
isPressed = false;
}
}
isPressed = true;
break;
case GpioAction::MENU_NAVIGATION_BACK:
if (!screenIsPrompting) {
if (previousMenu != nullptr) {
currentMenu = previousMenu;
previousMenu = nullptr;
menuIndex = 0;
changeIndex = true;
gpMenu->setMenuData(currentMenu);
gpMenu->setMenuTitle(MAIN_MENU_NAME);
} else {
exitToScreen = DisplayMode::BUTTONS;
exitToScreenBeforePrompt = DisplayMode::BUTTONS;
isPressed = false;
}
} else {
// back again goes back to the menu
screenIsPrompting = false;
isPressed = false;
}
isPressed = true;
break;
default:
break;
}
prevButtonState = buttonState;
if (changeIndex) gpMenu->setIndex(menuIndex);
}
void MainMenuScreen::saveAndExit() {
saveOptions();
}
int32_t MainMenuScreen::modeValue() {
return -1;
}
/*
void testMenu();
void MainMenuScreen::selectInputMode() {
if (currentMenu->at(menuIndex).optionValue != -1) {
InputMode valueToSave = (InputMode)currentMenu->at(menuIndex).optionValue;
prevInputMode = Storage::getInstance().GetGamepad()->getOptions().inputMode;
updateInputMode = valueToSave;
std::vector<MenuEntry> mainMenu = {
{"Menu 1", NULL, std::bind(&DisplayAddon::testMenu, this)},
{"Menu 2", NULL, std::bind(&DisplayAddon::testMenu, this)},
{"Menu 3", NULL, std::bind(&DisplayAddon::testMenu, this)},
{"Menu 4", NULL, std::bind(&DisplayAddon::testMenu, this)},
{"Menu 5", NULL, std::bind(&DisplayAddon::testMenu, this)},
{"Menu 6", NULL, std::bind(&DisplayAddon::testMenu, this)},
{"Menu 7", NULL, std::bind(&DisplayAddon::testMenu, this)},
{"Menu 8", NULL, std::bind(&DisplayAddon::testMenu, this)},
};
if (prevInputMode != valueToSave) {
// input mode requires a save and reboot
changeRequiresReboot = true;
changeRequiresSave = true;
}
}
}
std::vector<MenuEntry>* currentMenu = &mainMenu;
*/
int32_t MainMenuScreen::currentInputMode() {
return updateInputMode;
}
void MainMenuScreen::selectDPadMode() {
if (currentMenu->at(menuIndex).optionValue != -1) {
DpadMode valueToSave = (DpadMode)currentMenu->at(menuIndex).optionValue;
prevDpadMode = Storage::getInstance().GetGamepad()->getOptions().dpadMode;
updateDpadMode = valueToSave;
if (prevDpadMode != valueToSave) changeRequiresSave = true;
}
}
int32_t MainMenuScreen::currentDpadMode() {
return updateDpadMode;
}
void MainMenuScreen::selectSOCDMode() {
if (currentMenu->at(menuIndex).optionValue != -1) {
SOCDMode valueToSave = (SOCDMode)currentMenu->at(menuIndex).optionValue;
prevSocdMode = Storage::getInstance().GetGamepad()->getOptions().socdMode;
updateSocdMode = valueToSave;
if (prevDpadMode != valueToSave) changeRequiresSave = true;
}
}
int32_t MainMenuScreen::currentSOCDMode() {
return updateSocdMode;
}
void MainMenuScreen::resetOptions() {
if (changeRequiresSave) {
if (prevInputMode != updateInputMode) updateInputMode = prevInputMode;
if (prevDpadMode != updateDpadMode) updateDpadMode = prevDpadMode;
if (prevSocdMode != updateSocdMode) updateSocdMode = prevSocdMode;
if (prevProfile != updateProfile) updateProfile = prevProfile;
if (prevFocus != updateFocus) updateFocus = prevFocus;
if (prevTurbo != updateTurbo) updateTurbo = prevTurbo;
}
changeRequiresSave = false;
changeRequiresReboot = false;
screenIsPrompting = false;
}
void MainMenuScreen::saveOptions() {
GamepadOptions& options = Storage::getInstance().getGamepadOptions();
if (changeRequiresSave) {
bool saveHasChanged = false;
if (prevInputMode != updateInputMode) {
options.inputMode = updateInputMode;
saveHasChanged = true;
}
if (prevDpadMode != updateDpadMode) {
options.dpadMode = updateDpadMode;
saveHasChanged = true;
}
if (prevSocdMode != updateSocdMode) {
options.socdMode = updateSocdMode;
saveHasChanged = true;
}
if (prevProfile != updateProfile) {
options.profileNumber = updateProfile;
saveHasChanged = true;
}
if (prevFocus != updateFocus) {
Storage::getInstance().getAddonOptions().focusModeOptions.enabled = updateFocus;
saveHasChanged = true;
}
if (prevTurbo != updateTurbo) {
Storage::getInstance().getAddonOptions().turboOptions.enabled = updateTurbo;
saveHasChanged = true;
}
if (saveHasChanged) {
EventManager::getInstance().triggerEvent(new GPStorageSaveEvent(true, changeRequiresReboot));
screenIsPrompting = false;
}
changeRequiresSave = false;
changeRequiresReboot = false;
}
if (exitToScreenBeforePrompt != -1) {
exitToScreen = exitToScreenBeforePrompt;
exitToScreenBeforePrompt = -1;
}
}
void MainMenuScreen::selectProfile() {
if (currentMenu->at(menuIndex).optionValue != -1) {
uint8_t valueToSave = currentMenu->at(menuIndex).optionValue;
prevProfile = Storage::getInstance().GetGamepad()->getOptions().profileNumber;
updateProfile = valueToSave;
if (prevProfile != valueToSave) changeRequiresSave = true;
}
}
int32_t MainMenuScreen::currentProfile() {
return updateProfile;
}
void MainMenuScreen::selectFocusMode() {
if (currentMenu->at(menuIndex).optionValue != -1) {
uint8_t valueToSave = currentMenu->at(menuIndex).optionValue;
prevFocus = Storage::getInstance().getAddonOptions().focusModeOptions.enabled;
updateFocus = valueToSave;
if (prevFocus != valueToSave) changeRequiresSave = true;
}
}
int32_t MainMenuScreen::currentFocusMode() {
return updateFocus;
}
void MainMenuScreen::selectTurboMode() {
if (currentMenu->at(menuIndex).optionValue != -1) {
uint8_t valueToSave = currentMenu->at(menuIndex).optionValue;
prevTurbo = Storage::getInstance().getAddonOptions().turboOptions.enabled;
updateTurbo = valueToSave;
if (updateTurbo != valueToSave) changeRequiresSave = true;
}
}
int32_t MainMenuScreen::currentTurboMode() {
return updateTurbo;
}

View File

@@ -2,6 +2,10 @@
#include "storagemanager.h"
#include "enums.pb.h"
void EventManager::init() {
clearEventHandlers();
}
void EventManager::registerEventHandler(GPEventType eventType, EventFunction handler) {
typename std::vector<EventEntry>::iterator it = std::find_if(eventList.begin(), eventList.end(), [&eventType](const EventEntry& entry) { return entry.first == eventType; });
@@ -26,4 +30,8 @@ void EventManager::triggerEvent(GPEvent* event) {
}
}
delete event;
}
}
void EventManager::clearEventHandlers() {
}

View File

@@ -656,12 +656,47 @@ void Gamepad::processHotkeyAction(GamepadHotkey action) {
reqSave = true;
}
break;
case HOTKEY_MENU_NAV_UP:
if (action != lastAction) {
EventManager::getInstance().triggerEvent(new GPMenuNavigateEvent(GpioAction::MENU_NAVIGATION_UP));
}
break;
case HOTKEY_MENU_NAV_DOWN:
if (action != lastAction) {
EventManager::getInstance().triggerEvent(new GPMenuNavigateEvent(GpioAction::MENU_NAVIGATION_DOWN));
}
break;
case HOTKEY_MENU_NAV_LEFT:
if (action != lastAction) {
EventManager::getInstance().triggerEvent(new GPMenuNavigateEvent(GpioAction::MENU_NAVIGATION_LEFT));
}
break;
case HOTKEY_MENU_NAV_RIGHT:
if (action != lastAction) {
EventManager::getInstance().triggerEvent(new GPMenuNavigateEvent(GpioAction::MENU_NAVIGATION_RIGHT));
}
break;
case HOTKEY_MENU_NAV_SELECT:
if (action != lastAction) {
EventManager::getInstance().triggerEvent(new GPMenuNavigateEvent(GpioAction::MENU_NAVIGATION_SELECT));
}
break;
case HOTKEY_MENU_NAV_BACK:
if (action != lastAction) {
EventManager::getInstance().triggerEvent(new GPMenuNavigateEvent(GpioAction::MENU_NAVIGATION_BACK));
}
break;
case HOTKEY_MENU_NAV_TOGGLE:
if (action != lastAction) {
EventManager::getInstance().triggerEvent(new GPMenuNavigateEvent(GpioAction::MENU_NAVIGATION_TOGGLE));
}
break;
default: // Unknown action
return;
}
// only save if requested
if (reqSave) {
Storage::getInstance().save();
EventManager::getInstance().triggerEvent(new GPStorageSaveEvent(true));
}
}

View File

@@ -47,6 +47,9 @@
static const uint32_t REBOOT_HOTKEY_ACTIVATION_TIME_MS = 50;
static const uint32_t REBOOT_HOTKEY_HOLD_TIME_MS = 4000;
const static uint32_t rebootDelayMs = 500;
static absolute_time_t rebootDelayTimeout = nil_time;
void GP2040::setup() {
Storage::getInstance().init();
@@ -184,6 +187,9 @@ void GP2040::setup() {
// before USB host will be used so we can force it to ignore the check
Storage::getInstance().save(true);
}
// register system event handlers
EventManager::getInstance().registerEventHandler(GP_EVENT_STORAGE_SAVE, GPEVENT_CALLBACK(this->handleStorageSave(event)));
}
/**
@@ -317,6 +323,24 @@ void GP2040::run() {
addons.ProcessAddons(ADDON_PROCESS::CORE0_USBREPORT);
tud_task(); // TinyUSB Task update
if (rebootRequested) {
rebootRequested = false;
if (saveRequested) {
saveRequested = false;
Storage::getInstance().save(true);
}
rebootDelayTimeout = make_timeout_time_ms(rebootDelayMs);
} else {
if (saveRequested) {
saveRequested = false;
Storage::getInstance().save(true);
}
}
if (!is_nil_time(rebootDelayTimeout) && time_reached(rebootDelayTimeout)) {
System::reboot(System::BootMode::DEFAULT);
}
}
}
@@ -526,3 +550,12 @@ void GP2040::checkProcessedState(GamepadState prevState, GamepadState currState)
EventManager::getInstance().triggerEvent(new GPAnalogProcessedMoveEvent(currState.lx, currState.ly, currState.rx, currState.ry, currState.lt, currState.rt));
}
}
void GP2040::handleStorageSave(GPEvent* e) {
saveRequested = true;
rebootRequested = ((GPStorageSaveEvent*)e)->restartAfterSave;
}
void GP2040::handleSystemReboot(GPEvent* e) {
rebootRequested = true;
}

View File

@@ -46,6 +46,10 @@ void GPGFX_OBD_SSD1306::drawPixel(uint8_t x, uint8_t y, uint32_t color) {
obdSetPixel(&obd, x, y, color, 1);
}
uint32_t GPGFX_OBD_SSD1306::getPixel(uint8_t x, uint8_t y) {
return 0;
}
void GPGFX_OBD_SSD1306::drawText(uint8_t x, uint8_t y, std::string text, uint8_t invert) {
obdWriteString(&obd, 0, x, y, (char*)text.c_str(), FONT_6x8, 0, 1);
}
@@ -62,7 +66,7 @@ void GPGFX_OBD_SSD1306::drawRectangle(uint16_t x, uint16_t y, uint16_t width, ui
obdRectangle(&obd, x, y, width, height, color, filled);
}
void GPGFX_OBD_SSD1306::drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority) {
void GPGFX_OBD_SSD1306::drawSprite(uint8_t* spriteData, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority, double scale) {
obdDrawSprite(&obd, spriteData, width, height, pitch, x, y, priority);
}

View File

@@ -114,6 +114,25 @@ void GPGFX_TinySSD1306::clear() {
memset(frameBuffer, 0, MAX_SCREEN_SIZE);
}
uint32_t GPGFX_TinySSD1306::getPixel(uint8_t x, uint8_t y) {
uint16_t row, bitIndex;
uint32_t result = 0;
if ((x<MAX_SCREEN_WIDTH) and (y<MAX_SCREEN_HEIGHT))
{
if (this->screenType == ScreenAlternatives::SCREEN_132x64) {
x+=2;
}
row=((y/8)*MAX_SCREEN_WIDTH)+x;
bitIndex=y % 8;
result = (frameBuffer[row] >> bitIndex) && 0x01;
}
return result;
}
void GPGFX_TinySSD1306::drawPixel(uint8_t x, uint8_t y, uint32_t color) {
uint16_t row, bitIndex;
@@ -395,20 +414,22 @@ void GPGFX_TinySSD1306::drawPolygon(uint16_t x, uint16_t y, uint16_t radius, uin
}
}
void GPGFX_TinySSD1306::drawSprite(uint8_t* image, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority) {
void GPGFX_TinySSD1306::drawSprite(uint8_t* image, uint16_t width, uint16_t height, uint16_t pitch, uint16_t x, uint16_t y, uint8_t priority, double scale) {
uint8_t spriteByte;
uint8_t spriteBit;
uint8_t spriteX, spriteY;
uint8_t color;
for (spriteY = 0; spriteY < height; spriteY++) {
for (spriteX = 0; spriteX < width; spriteX++) {
for (uint16_t scaledY = 0; scaledY < height * scale; ++scaledY) {
for (uint16_t scaledX = 0; scaledX < width * scale; ++scaledX) {
spriteX = scaledX / scale;
spriteY = scaledY / scale;
spriteBit = spriteX % 8;
//spriteByte = image[(spriteY * (width / 8)) + (spriteX / 8)];
spriteByte = image[(spriteY * ((width + 7) / 8)) + (spriteX / 8)];
color = ((spriteByte >> (7 - spriteBit)) & 0x01);
drawPixel(x+spriteX, y+spriteY, color);
drawPixel(x + scaledX, y + scaledY, color);
}
}
}

View File

@@ -4,13 +4,35 @@
#include "enums.pb.h"
LayoutManager::LayoutList LayoutManager::getLayoutA() {
uint16_t layoutLeft = Storage::getInstance().getDisplayOptions().buttonLayout;
return getLeftLayout(layoutLeft);
const DisplayOptions& options = Storage::getInstance().getDisplayOptions();
uint16_t layoutLeft = options.buttonLayout;
if (options.buttonLayoutOrientation != BUTTON_ORIENTATION_DEFAULT) {
uint16_t layoutRight = options.buttonLayoutRight;
LayoutManager::LayoutList rightLayout = getRightLayout(layoutRight);
if (options.buttonLayoutOrientation == BUTTON_ORIENTATION_SWITCHED) {
return adjustByOffset(rightLayout, -64);
} else {
return adjustByOffset(flipHorizontally(rightLayout, 64, 0, 128, 0), -64);
}
} else {
return getLeftLayout(layoutLeft);
}
}
LayoutManager::LayoutList LayoutManager::getLayoutB() {
uint16_t layoutRight = Storage::getInstance().getDisplayOptions().buttonLayoutRight;
return getRightLayout(layoutRight);
const DisplayOptions& options = Storage::getInstance().getDisplayOptions();
uint16_t layoutRight = options.buttonLayoutRight;
if (options.buttonLayoutOrientation != BUTTON_ORIENTATION_DEFAULT) {
uint16_t layoutLeft = options.buttonLayout;
LayoutManager::LayoutList leftLayout = getLeftLayout(layoutLeft);
if (options.buttonLayoutOrientation == BUTTON_ORIENTATION_SWITCHED) {
return adjustByOffset(leftLayout, 64);
} else {
return adjustByOffset(flipHorizontally(leftLayout, 0, 0, 64, 0), 64);
}
} else {
return getRightLayout(layoutRight);
}
}
std::string LayoutManager::getLayoutAName() {
@@ -145,6 +167,8 @@ LayoutManager::LayoutList LayoutManager::getRightLayout(uint16_t index) {
return this->drawCapcom6();
case BUTTON_LAYOUT_SEGA2P:
return this->drawSega2p();
case BUTTON_LAYOUT_SEGA2P_6B:
return this->drawSega2p6b();
case BUTTON_LAYOUT_NOIR8:
return this->drawNoir8();
case BUTTON_LAYOUT_KEYBOARDB:
@@ -155,6 +179,8 @@ LayoutManager::LayoutList LayoutManager::getRightLayout(uint16_t index) {
return this->drawBlankB();
case BUTTON_LAYOUT_VLXB:
return this->drawVLXB();
case BUTTON_LAYOUT_VLXB_6B:
return this->drawVLXB6B();
case BUTTON_LAYOUT_FIGHTBOARD:
return this->drawFightboard();
case BUTTON_LAYOUT_FIGHTBOARD_STICK_MIRRORED:
@@ -255,6 +281,52 @@ LayoutManager::LayoutList LayoutManager::adjustByCustomSettings(LayoutManager::L
return layout;
}
LayoutManager::LayoutList LayoutManager::adjustByOffset(LayoutManager::LayoutList layout, int16_t originX, int16_t originY) {
if (layout.size() > 0) {
int16_t minX = INT16_MAX;
int16_t maxX = INT16_MIN;
for (uint16_t elementCtr = 0; elementCtr < layout.size(); elementCtr++) {
int16_t newX = layout[elementCtr].parameters.x1 + originX;
if (((GPShape_Type)layout[elementCtr].parameters.shape == GP_SHAPE_ELLIPSE) || ((GPShape_Type)layout[elementCtr].parameters.shape == GP_SHAPE_POLYGON)) {
newX = (layout[elementCtr].parameters.x1-(layout[elementCtr].parameters.x2)) + originX;
} else if ((GPShape_Type)layout[elementCtr].parameters.shape == GP_SHAPE_SQUARE) {
if (originX > 0) newX = layout[elementCtr].parameters.x2 + originX;
}
minX = std::min(minX, newX);
maxX = std::max(maxX, newX);
}
int16_t offsetX = 0;
if (minX < 0) {
offsetX = -minX;
} else if (maxX > 127) {
offsetX = 127 - maxX;
}
// Apply the calculated adjustment to all objects
for (uint16_t elementCtr = 0; elementCtr < layout.size(); elementCtr++) {
layout[elementCtr].parameters.x1 += originX + offsetX;
if ((GPShape_Type)layout[elementCtr].parameters.shape == GP_SHAPE_SQUARE) {
layout[elementCtr].parameters.x2 += originX + offsetX;
}
layout[elementCtr].parameters.y1 += originY; // Apply y offset directly
}
}
return layout;
}
LayoutManager::LayoutList LayoutManager::flipHorizontally(LayoutList layout, int16_t startX, int16_t startY, int16_t endX, int16_t endY) {
if (layout.size() > 0) {
for (uint16_t elementCtr = 0; elementCtr < layout.size(); elementCtr++) {
int16_t originalX = layout[elementCtr].parameters.x1;
layout[elementCtr].parameters.x1 = (endX-1) - (originalX - startX);
}
}
return layout;
}
LayoutManager::LayoutList LayoutManager::drawStickless()
{
return BUTTON_GROUP_STICKLESS;
@@ -345,6 +417,11 @@ LayoutManager::LayoutList LayoutManager::drawVLXB()
return BUTTON_GROUP_VLXB;
}
LayoutManager::LayoutList LayoutManager::drawVLXB6B()
{
return BUTTON_GROUP_VLXB_6B;
}
LayoutManager::LayoutList LayoutManager::drawFightboard()
{
return BUTTON_GROUP_FIGHTBOARD;
@@ -360,6 +437,11 @@ LayoutManager::LayoutList LayoutManager::drawSega2p()
return BUTTON_GROUP_SEGA_2P;
}
LayoutManager::LayoutList LayoutManager::drawSega2p6b()
{
return BUTTON_GROUP_SEGA_2P_6B;
}
LayoutManager::LayoutList LayoutManager::drawNoir8()
{
return BUTTON_GROUP_NOIR8;

View File

@@ -56,6 +56,7 @@ app.get('/api/getDisplayOptions', (req, res) => {
invertDisplay: 1,
buttonLayout: 0,
buttonLayoutRight: 3,
buttonLayoutOrientation: 0,
splashMode: 3,
splashChoice: 0,
splashDuration: 0,
@@ -77,7 +78,18 @@ app.get('/api/getDisplayOptions', (req, res) => {
},
displaySaverTimeout: 0,
displaySaverMode: 0,
turnOffWhenSuspended: 0,
inputMode: 1,
turboMode: 1,
dpadMode: 1,
socdMode: 1,
macroMode: 1,
profileMode: 0,
inputHistoryEnabled: 0,
inputHistoryLength: 21,
inputHistoryCol: 0,
inputHistoryRow: 7,
};
console.log('data', data);
return res.send(data);
@@ -510,10 +522,6 @@ app.get('/api/getAddonsOptions', (req, res) => {
TurboInputEnabled: 1,
WiiExtensionAddonEnabled: 1,
SNESpadAddonEnabled: 1,
InputHistoryAddonEnabled: 1,
inputHistoryLength: 21,
inputHistoryCol: 0,
inputHistoryRow: 7,
Analog1256Enabled: 1,
analog1256Block: 0,
analog1256CsPin: -1,

View File

@@ -1,99 +0,0 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { FormCheck, Row } from 'react-bootstrap';
import * as yup from 'yup';
import Section from '../Components/Section';
import FormControl from '../Components/FormControl';
export const inputHistoryScheme = {
InputHistoryAddonEnabled: yup
.number()
.required()
.label('Input History Enabled'),
inputHistoryLength: yup
.number()
.label('Input History Length')
.validateRangeWhenValue('InputHistoryAddonEnabled', 1, 21),
inputHistoryCol: yup
.number()
.label('Col')
.validateRangeWhenValue('InputHistoryAddonEnabled', 0, 20),
inputHistoryRow: yup
.number()
.label('Row')
.validateRangeWhenValue('InputHistoryAddonEnabled', 0, 7),
};
export const inputHistoryState = {
InputHistoryAddonEnabled: 0,
inputHistoryLength: 21,
inputHistoryCol: 0,
inputHistoryRow: 7,
};
const InputHistory = ({ values, errors, handleChange, handleCheckbox }) => {
const { t } = useTranslation();
return (
<Section title={t('AddonsConfig:input-history-header-text')}>
<div id="InputHistoryOptions" hidden={!values.InputHistoryAddonEnabled}>
<Row className="mb-3">
<FormControl
type="number"
label={t('AddonsConfig:input-history-length-label')}
name="inputHistoryLength"
className="form-control-sm"
groupClassName="col-sm-3 mb-3"
value={values.inputHistoryLength}
error={errors.inputHistoryLength}
isInvalid={errors.inputHistoryLength}
onChange={handleChange}
min={1}
max={21}
/>
<FormControl
type="number"
label={t('AddonsConfig:input-history-col-label')}
name="inputHistoryCol"
className="form-control-sm"
groupClassName="col-sm-3 mb-3"
value={values.inputHistoryCol}
error={errors.inputHistoryCol}
isInvalid={errors.inputHistoryCol}
onChange={handleChange}
min={0}
max={20}
/>
<FormControl
type="number"
label={t('AddonsConfig:input-history-row-label')}
name="inputHistoryRow"
className="form-control-sm"
groupClassName="col-sm-3 mb-3"
value={values.inputHistoryRow}
error={errors.inputHistoryRow}
isInvalid={errors.inputHistoryRow}
onChange={handleChange}
min={0}
max={7}
/>
</Row>
</div>
<FormCheck
label={t('Common:switch-enabled')}
type="switch"
id="InputHistoryButton"
reverse
isInvalid={false}
checked={Boolean(values.InputHistoryAddonEnabled)}
onChange={(e) => {
handleCheckbox('InputHistoryAddonEnabled', values);
handleChange(e);
}}
/>
</Section>
);
};
export default InputHistory;

View File

@@ -74,6 +74,13 @@ export const BUTTON_ACTIONS = {
BUTTON_PRESS_INPUT_REVERSE: 69,
SUSTAIN_FOCUS_MODE: 70,
SUSTAIN_4_8_WAY_MODE: 71,
MENU_NAVIGATION_UP: 72,
MENU_NAVIGATION_DOWN: 73,
MENU_NAVIGATION_LEFT: 74,
MENU_NAVIGATION_RIGHT: 75,
MENU_NAVIGATION_SELECT: 76,
MENU_NAVIGATION_BACK: 77,
MENU_NAVIGATION_TOGGLE: 78,
} as const;
export const PIN_DIRECTIONS = {

View File

@@ -8,6 +8,10 @@ export default {
'hardware-header': 'Hardware Options',
'screen-header': 'Screen Options',
'layout-header': 'Layout Options',
'mode-header': 'Mode Options',
'button-layout-header': 'Button Layout',
'status-layout-header': 'Status Bar Layout',
'history-layout-header': 'Input History Layout',
},
table: {
header:
@@ -25,6 +29,7 @@ export default {
'invert-display-label': 'Invert Display',
'button-layout-label': 'Button Layout (Left)',
'button-layout-right-label': 'Button Layout (Right)',
'button-layout-orientation': 'Button Layout Orientation',
'button-layout-custom-header': 'Custom Button Layout Params',
'button-layout-custom-left-label': 'Layout Left',
'button-layout-custom-right-label': 'Layout Right',
@@ -35,12 +40,46 @@ export default {
'splash-mode-label': 'Splash Mode',
'splash-duration-label': 'Splash Duration (seconds, 0 for Always On)',
'display-saver-timeout-label': 'Display Saver Timeout (minutes)',
'screen-saver-mode-label': 'Display Saver Mode',
'inverted-label': 'Inverted',
'power-management-header': 'Power Management',
'turn-off-when-suspended': 'Turn Off When Suspended',
'flip-display-none': 'None',
'flip-display-flip': 'Flip',
'flip-display-mirror': 'Mirror',
'flip-display-flip-mirror': 'Flip and Mirror',
'input-history-label': 'Input History',
'display-state': {
'disabled': 'Disabled',
'enabled': 'Enabled'
},
'flip-display': {
'none': 'None',
'flip': 'Flip',
'mirror': 'Mirror',
'flip-mirror': 'Flip and Mirror',
},
'splash-modes': {
'enabled': 'Enabled (Custom Splash Screen)',
'close-in': 'Logo Close In',
'close-in-custom': 'Logo Close In Custom',
'disabled': 'Disabled',
},
'saver-modes': {
'display-off': 'Display Off',
'snow': 'Snow',
'bounce': 'Logo Bounce',
'pipes': 'Pipes',
'toast': 'Toast',
},
'layout-modes': {
'standard': 'Default',
'southpaw': 'Southpaw',
'switched': 'Switched',
},
'status-header': {
'input-mode': 'Input Mode',
'turbo-mode': 'Turbo',
'dpad-mode': 'D-Pad Mode',
'socd-mode': 'SOCD Mode',
'macro-mode': 'Macro',
'profile-mode': 'Profile',
},
},
};

View File

@@ -49,12 +49,14 @@ export default {
BUTTON_LAYOUT_CAPCOM: 'Capcom',
BUTTON_LAYOUT_CAPCOM6: 'Capcom 6',
BUTTON_LAYOUT_SEGA2P: 'Sega 2P',
BUTTON_LAYOUT_SEGA2P_6B: 'Sega 2P 6',
BUTTON_LAYOUT_NOIR8: 'Noir 8',
BUTTON_LAYOUT_KEYBOARDB: 'Keyboard',
BUTTON_LAYOUT_DANCEPADB: 'Dancepad',
BUTTON_LAYOUT_TWINSTICKB: 'Twinstick',
BUTTON_LAYOUT_BLANKB: 'Blank',
BUTTON_LAYOUT_VLXB: 'VLX',
BUTTON_LAYOUT_VLXB_6B: 'VLX 6',
BUTTON_LAYOUT_FIGHTBOARD: 'Fightboard',
BUTTON_LAYOUT_FIGHTBOARD_STICK_MIRRORED: 'Fightboard Mirrored',
BUTTON_LAYOUT_CUSTOM: 'Custom',

View File

@@ -99,5 +99,12 @@ export default {
BUTTON_PRESS_INPUT_REVERSE: 'Reverse Input',
SUSTAIN_FOCUS_MODE: 'Focus Mode Enable',
SUSTAIN_4_8_WAY_MODE: 'Toggle 4-Way Mode',
MENU_NAVIGATION_UP: 'Menu Up',
MENU_NAVIGATION_DOWN: 'Menu Down',
MENU_NAVIGATION_LEFT: 'Menu Left',
MENU_NAVIGATION_RIGHT: 'Menu Right',
MENU_NAVIGATION_SELECT: 'Menu Select',
MENU_NAVIGATION_BACK: 'Menu Back',
MENU_NAVIGATION_TOGGLE: 'Menu Toggle',
},
};

View File

@@ -130,6 +130,13 @@ export default {
'save-config': 'Save Config',
'next-profile': 'Next Profile',
'previous-profile': 'Previous Profile',
'menu-nav-up': 'Menu Up',
'menu-nav-down': 'Menu Down',
'menu-nav-left': 'Menu Left',
'menu-nav-right': 'Menu Right',
'menu-nav-select': 'Menu Select',
'menu-nav-back': 'Menu Back',
'menu-nav-toggle': 'Menu Toggle',
},
'forced-setup-mode-label': 'Forced Setup Mode',
'forced-setup-mode-options': {

View File

@@ -47,10 +47,6 @@ import FocusMode, {
} from '../Addons/FocusMode';
import Keyboard, { keyboardScheme, keyboardState } from '../Addons/Keyboard';
import GamepadUSBHost, { gamepadUSBHostScheme, gamepadUSBHostState} from '../Addons/GamepadUSBHost';
import InputHistory, {
inputHistoryScheme,
inputHistoryState,
} from '../Addons/InputHistory';
import Rotary, { rotaryScheme, rotaryState } from '../Addons/Rotary';
import PCF8575, { pcf8575Scheme, pcf8575State } from '../Addons/PCF8575';
import DRV8833Rumble, {
@@ -79,7 +75,6 @@ const schema = yup.object().shape({
...wiiScheme,
...focusModeScheme,
...keyboardScheme,
...inputHistoryScheme,
...rotaryScheme,
...pcf8575Scheme,
...drv8833RumbleScheme,
@@ -104,7 +99,6 @@ const defaultValues = {
...snesState,
...focusModeState,
...keyboardState,
...inputHistoryState,
...rotaryState,
...pcf8575State,
...drv8833RumbleState,
@@ -130,7 +124,6 @@ const ADDONS = [
FocusMode,
Keyboard,
GamepadUSBHost,
InputHistory,
Rotary,
PCF8575,
DRV8833Rumble,

File diff suppressed because it is too large Load Diff

View File

@@ -287,6 +287,13 @@ const HOTKEY_ACTIONS = [
{ labelKey: 'hotkey-actions.dpad-down', value: 39 },
{ labelKey: 'hotkey-actions.dpad-left', value: 40 },
{ labelKey: 'hotkey-actions.dpad-right', value: 41 },
{ labelKey: 'hotkey-actions.menu-nav-up', value: 44 },
{ labelKey: 'hotkey-actions.menu-nav-down', value: 45 },
{ labelKey: 'hotkey-actions.menu-nav-left', value: 46 },
{ labelKey: 'hotkey-actions.menu-nav-right', value: 47 },
{ labelKey: 'hotkey-actions.menu-nav-select', value: 48 },
{ labelKey: 'hotkey-actions.menu-nav-back', value: 49 },
{ labelKey: 'hotkey-actions.menu-nav-toggle', value: 50 },
];
const FORCED_SETUP_MODES = [