summaryrefslogtreecommitdiff
path: root/src/extras
diff options
context:
space:
mode:
Diffstat (limited to 'src/extras')
-rw-r--r--src/extras/frontendoption.cpp233
-rw-r--r--src/extras/frontendoption.h121
2 files changed, 277 insertions, 77 deletions
diff --git a/src/extras/frontendoption.cpp b/src/extras/frontendoption.cpp
index 51814f35..3214bbfd 100644
--- a/src/extras/frontendoption.cpp
+++ b/src/extras/frontendoption.cpp
@@ -2,14 +2,24 @@
#ifdef CUSTOM_FRONTEND_OPTIONS
#include "frontendoption.h"
+#include "Text.h"
int numCustomFrontendOptions = 0;
FrontendOption *customFrontendOptions;
-int optionCursor = -1;
-eMenuScreen currentMenu;
+int numCustomFrontendScreens = 0;
+FrontendScreen* customFrontendScreens;
-void ChangeScreen(eMenuScreen screen, int option, bool fadeIn)
+int numFrontendOptionReplacements = 0;
+CMenuScreen::CMenuEntry* frontendOptionReplacements;
+
+int lastOgScreen = MENUPAGES; // means no new pages
+
+int optionCursor = -2;
+int currentMenu;
+bool optionOverwrite = false;
+
+void ChangeScreen(int screen, int option, bool fadeIn)
{
FrontEndMenuManager.m_nPrevScreen = FrontEndMenuManager.m_nCurrScreen;
FrontEndMenuManager.m_nCurrScreen = screen;
@@ -27,7 +37,7 @@ void GoBack(bool fadeIn)
FrontEndMenuManager.ThingsToDoBeforeGoingBack();
- ChangeScreen((eMenuScreen)screen, option, fadeIn);
+ ChangeScreen(screen, option, fadeIn);
}
uint8
@@ -43,31 +53,89 @@ GetNumberOfMenuOptions(int screen)
return Rows;
}
+uint8
+GetLastMenuScreen()
+{
+ uint8 page = -1;
+ for (int i = 0; i < MENUPAGES; i++) {
+ if (strcmp(aScreens[i].m_ScreenName, "") == 0 && aScreens[i].unk == 0)
+ break;
+
+ ++page;
+ }
+ return page;
+}
+
// Used before populating options, but effective in InitialiseChangedLanguageSettings and debugmenu
void
RemoveCustomFrontendOptions()
{
- if (numCustomFrontendOptions == 0)
- return;
+ if (numCustomFrontendOptions != 0) {
- for (int i = 0; i < MENUPAGES; i++) {
- for (int j = 0; j < NUM_MENUROWS; j++) {
- if (aScreens[i].m_aEntries[j].m_Action == MENUACTION_TRIGGERFUNC) {
- int k;
- for (k = j; k < NUM_MENUROWS-1; k++) {
- memcpy(&aScreens[i].m_aEntries[k], &aScreens[i].m_aEntries[k+1], sizeof(CMenuScreen::CMenuEntry));
+ for (int i = 0; i < MENUPAGES; i++) {
+ for (int j = 0; j < NUM_MENUROWS; j++) {
+ if (aScreens[i].m_aEntries[j].m_SaveSlot == SAVESLOT_CFO) {
+ int ogOptionId = customFrontendOptions[aScreens[i].m_aEntries[j].m_TargetMenu].ogOptionId;
+ if (ogOptionId == -1) {
+ int k;
+ for (k = j; k < NUM_MENUROWS - 1; k++) {
+ memcpy(&aScreens[i].m_aEntries[k], &aScreens[i].m_aEntries[k + 1], sizeof(CMenuScreen::CMenuEntry));
+ }
+ aScreens[i].m_aEntries[k].m_Action = MENUACTION_NOTHING;
+ aScreens[i].m_aEntries[k].m_SaveSlot = SAVESLOT_NONE;
+ aScreens[i].m_aEntries[k].m_EntryName[0] = '\0';
+ j--;
+ } else {
+ memcpy(&aScreens[i].m_aEntries[j], &frontendOptionReplacements[ogOptionId], sizeof(CMenuScreen::CMenuEntry));
+ }
}
- aScreens[i].m_aEntries[k].m_Action = MENUACTION_NOTHING;
- aScreens[i].m_aEntries[k].m_EntryName[0] = '\0';
- j--;
}
}
+ free(customFrontendOptions);
+ numCustomFrontendOptions = 0;
+
+ if (numFrontendOptionReplacements != 0) {
+ free(frontendOptionReplacements);
+ numFrontendOptionReplacements = 0;
+ }
+ }
+
+ if (numCustomFrontendScreens == 0)
+ return;
+
+ for (int i = 0; i < MENUPAGES; i++) {
+ if (i > lastOgScreen) {
+ aScreens[i].m_ScreenName[0] = '\0';
+ aScreens[i].unk = 0;
+ }
}
- free(customFrontendOptions);
- numCustomFrontendOptions = 0;
+ free(customFrontendScreens);
+ numCustomFrontendScreens = 0;
+ lastOgScreen = MENUPAGES;
+}
+
+int8 RegisterNewScreen(char *name, int prevPage)
+{
+ if (lastOgScreen == MENUPAGES)
+ lastOgScreen = GetLastMenuScreen();
+
+ numCustomFrontendScreens++;
+ if (numCustomFrontendScreens == 1)
+ customFrontendScreens = (FrontendScreen*)malloc(5 * sizeof(FrontendScreen));
+ else if (numCustomFrontendScreens % 5 == 1)
+ customFrontendScreens = (FrontendScreen*)realloc(customFrontendScreens, (numCustomFrontendScreens + 4) * sizeof(FrontendScreen));
+
+ assert(customFrontendScreens != nil && "Custom frontend screens can't be allocated");
+
+ int id = lastOgScreen + numCustomFrontendScreens;
+ assert(id < MENUPAGES && "No room for new custom frontend screens! Increase MENUPAGES");
+ strncpy(aScreens[id].m_ScreenName, name, 8);
+ aScreens[id].m_PreviousPage[0] = aScreens[id].m_PreviousPage[1] = prevPage;
+ aScreens[id].unk = 1;
+ return id;
}
-int8 RegisterNewOption(int screen)
+int8 RegisterNewOption()
{
numCustomFrontendOptions++;
if (numCustomFrontendOptions == 1)
@@ -77,97 +145,154 @@ int8 RegisterNewOption(int screen)
assert(customFrontendOptions != nil && "Custom frontend options can't be allocated");
- uint8 nth = GetNumberOfMenuOptions(screen);
+ uint8 numOptions = GetNumberOfMenuOptions(currentMenu);
+ uint8 curIdx;
if (optionCursor < 0) {
- if (optionCursor == -1) {
- if (!strcmp(aScreens[screen].m_aEntries[nth - 1].m_EntryName, "FEDS_TB") || !strcmp(aScreens[screen].m_aEntries[nth - 1].m_EntryName, "FESZ_CA")) {
- // Move back button one below
- memcpy(&aScreens[screen].m_aEntries[nth], &aScreens[screen].m_aEntries[nth - 1], sizeof(CMenuScreen::CMenuEntry));
- nth--;
+ optionCursor = curIdx = numOptions + optionCursor + 1;
+ } else
+ curIdx = optionCursor;
+
+ if (!optionOverwrite) {
+ if (aScreens[currentMenu].m_aEntries[curIdx].m_Action != MENUACTION_NOTHING) {
+ for (int i = numOptions - 1; i >= curIdx; i--) {
+ memcpy(&aScreens[currentMenu].m_aEntries[i + 1], &aScreens[currentMenu].m_aEntries[i], sizeof(CMenuScreen::CMenuEntry));
}
}
+ }
+ optionCursor++;
+
+ if (optionOverwrite) {
+ numFrontendOptionReplacements++;
+ if (numFrontendOptionReplacements == 1)
+ frontendOptionReplacements = (CMenuScreen::CMenuEntry*)malloc(5 * sizeof(CMenuScreen::CMenuEntry));
+ else if (numFrontendOptionReplacements % 5 == 1)
+ frontendOptionReplacements = (CMenuScreen::CMenuEntry*)realloc(frontendOptionReplacements, (numFrontendOptionReplacements + 4) * sizeof(CMenuScreen::CMenuEntry));
+
+ memcpy(&frontendOptionReplacements[numFrontendOptionReplacements - 1], &aScreens[currentMenu].m_aEntries[curIdx], sizeof(CMenuScreen::CMenuEntry));
+ customFrontendOptions[numCustomFrontendOptions - 1].ogOptionId = numFrontendOptionReplacements - 1;
} else {
- if (aScreens[screen].m_aEntries[optionCursor].m_Action != MENUACTION_NOTHING) {
- for (int i = nth - 1; i >= optionCursor; i--) {
- memcpy(&aScreens[screen].m_aEntries[i + 1], &aScreens[screen].m_aEntries[i], sizeof(CMenuScreen::CMenuEntry));
- }
- }
- nth = optionCursor;
- optionCursor++;
+ customFrontendOptions[numCustomFrontendOptions - 1].ogOptionId = -1;
}
+ customFrontendOptions[numCustomFrontendOptions - 1].screen = currentMenu;
- aScreens[screen].m_aEntries[nth].m_Action = MENUACTION_TRIGGERFUNC;
- aScreens[screen].m_aEntries[nth].m_TargetMenu = numCustomFrontendOptions - 1;
- aScreens[screen].m_aEntries[nth].m_EntryName[0] = 1; // just something to fool it
- return nth;
+ aScreens[currentMenu].m_aEntries[curIdx].m_Action = MENUACTION_TRIGGERFUNC;
+ aScreens[currentMenu].m_aEntries[curIdx].m_SaveSlot = SAVESLOT_CFO;
+ aScreens[currentMenu].m_aEntries[curIdx].m_TargetMenu = numCustomFrontendOptions - 1;
+ aScreens[currentMenu].m_aEntries[curIdx].m_EntryName[0] = 1; // just something to fool it
+ return curIdx;
}
-void FrontendOptionSetPosition(eMenuScreen screen, int8 option)
+void FrontendOptionSetCursor(int screen, int8 option, bool overwrite)
{
currentMenu = screen;
optionCursor = option;
+ optionOverwrite = overwrite;
}
-void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc)
+void FrontendOptionAddBuiltinAction(const wchar* leftText, int action, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc) {
+ int8 screenOptionOrder = RegisterNewOption();
+
+ FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1];
+
+ // To fool the Frontend, we will still display the text passed via first param.
+ switch (action) {
+ case MENUACTION_SCREENRES:
+ strcpy(aScreens[currentMenu].m_aEntries[screenOptionOrder].m_EntryName, "FED_RES");
+ break;
+ case MENUACTION_AUDIOHW:
+ strcpy(aScreens[currentMenu].m_aEntries[screenOptionOrder].m_EntryName, "FEA_3DH");
+ break;
+ }
+ aScreens[currentMenu].m_aEntries[screenOptionOrder].m_Action = action;
+ option.type = FEOPTION_BUILTIN_ACTION;
+ option.buttonPressFunc = buttonPressFunc;
+ TextCopy(option.leftText, leftText);
+ option.screenOptionOrder = screenOptionOrder;
+ option.returnPrevPageFunc = returnPrevPageFunc;
+ option.save = false;
+}
+
+void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save)
{
- int8 screenOptionOrder = RegisterNewOption(currentMenu);
+ int8 screenOptionOrder = RegisterNewOption();
FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1];
- option.screen = currentMenu;
option.type = FEOPTION_SELECT;
- option.leftText = leftText;
+ TextCopy(option.leftText, leftText);
option.rightTexts = rightTexts;
option.numRightTexts = numRightTexts;
option.value = var;
option.displayedValue = *var;
+ option.lastSavedValue = *var;
+ option.save = save;
option.onlyApplyOnEnter = onlyApplyOnEnter;
option.changeFunc = changeFunc;
option.screenOptionOrder = screenOptionOrder;
option.returnPrevPageFunc = returnPrevPageFunc;
}
-void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc drawFunc, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc)
+void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save)
{
- int8 screenOptionOrder = RegisterNewOption(currentMenu);
+ int8 screenOptionOrder = RegisterNewOption();
FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1];
- option.screen = currentMenu;
option.type = FEOPTION_DYNAMIC;
option.drawFunc = drawFunc;
option.buttonPressFunc = buttonPressFunc;
- option.leftText = leftText;
- option.onlyApplyOnEnter = false;
+ TextCopy(option.leftText, leftText);
+ option.value = var;
+ option.save = save;
option.screenOptionOrder = screenOptionOrder;
option.returnPrevPageFunc = returnPrevPageFunc;
}
-void FrontendOptionAddRedirect(const wchar* text, eMenuScreen to, int8 selectedOption, bool fadeIn)
+void FrontendOptionAddRedirect(const wchar* text, int to, int8 selectedOption, bool fadeIn)
{
- int8 screenOptionOrder = RegisterNewOption(currentMenu);
+ int8 screenOptionOrder = RegisterNewOption();
FrontendOption &option = customFrontendOptions[numCustomFrontendOptions - 1];
- option.screen = currentMenu;
option.type = FEOPTION_REDIRECT;
option.to = to;
option.option = selectedOption;
option.fadeIn = fadeIn;
- option.leftText = text;
- option.onlyApplyOnEnter = false;
+ TextCopy(option.leftText, text);
option.screenOptionOrder = screenOptionOrder;
option.returnPrevPageFunc = nil;
+ option.save = false;
}
void FrontendOptionAddBackButton(const wchar* text, bool fadeIn)
{
- int8 screenOptionOrder = RegisterNewOption(currentMenu);
+ int8 screenOptionOrder = RegisterNewOption();
FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1];
- option.screen = currentMenu;
option.type = FEOPTION_GOBACK;
option.fadeIn = fadeIn;
- option.leftText = text;
- option.onlyApplyOnEnter = false;
+ TextCopy(option.leftText, text);
option.screenOptionOrder = screenOptionOrder;
option.returnPrevPageFunc = nil;
+ option.save = false;
+}
+
+uint8 FrontendScreenAdd(char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight,
+ int8 font, float fontScaleX, float fontScaleY, int8 alignment, bool showLeftRightHelper, ReturnPrevPageFunc returnPrevPageFunc) {
+
+ uint8 screenOrder = RegisterNewScreen(gxtKey, prevPage);
+
+ FrontendScreen &screen = customFrontendScreens[numCustomFrontendScreens - 1];
+ screen.id = screenOrder;
+ screen.sprite = sprite;
+ screen.prevPage = prevPage;
+ strncpy(screen.name, gxtKey, 8);
+ screen.columnWidth = columnWidth;
+ screen.headerHeight = headerHeight;
+ screen.lineHeight = lineHeight;
+ screen.font = font;
+ screen.fontScaleX = fontScaleX;
+ screen.fontScaleY = fontScaleY;
+ screen.alignment = alignment;
+ screen.returnPrevPageFunc = returnPrevPageFunc;
+
+ return screenOrder;
}
#endif \ No newline at end of file
diff --git a/src/extras/frontendoption.h b/src/extras/frontendoption.h
index 7cfc09a7..9608870b 100644
--- a/src/extras/frontendoption.h
+++ b/src/extras/frontendoption.h
@@ -4,48 +4,102 @@
#ifdef CUSTOM_FRONTEND_OPTIONS
#include "Frontend.h"
-// Warning: All of the code relies on that you won't use more then NUM_MENUROWS(18) options on one page. Also congrats if you can make 18 options visible at once.
+// Warning:
+// All of the code relies on that you won't use more then NUM_MENUROWS(18) options on one page.
+// Also congrats if you can make 18 options visible at once.
+// About texts:
+// All text parameters accept wchar(including hardcoded wchar* and TheText.Get)
+// except FrontendScreenAdd(it's char[8] by the design of Frontend).
+// All texts reload if custom options reloaded too, which includes language changes and via live reload feature in debug menu!
-// Static/select: User allocates variable, passes it to function and it's set automatically from input among the strings given to function,
-// then you can handle ChangeFunc and ReturnPrevPageFunc if needed.
+// Execute direction:
+// All of the calls below eventually manipulate the aScreens array, so keep in mind to add/replace options in order,
+// i.e. don't set cursor to 8 first and then 3.
+
+// Live reload:
+// You can add/change/undo the new options in-game if you use VS. Change what you want, build the changed bits via "Edit and Continue",
+// and hit the "Reload custom frontend options" from debug menu. Or call CustomFrontendOptionsPopulate() from somewhere else.
+
+
+// -- Option types
+//
+// Static/select: You allocate the variable, pass it to function and game sets it from user input among the strings given to function,
+// then you can handle ChangeFunc(only called on enter if onlyApplyOnEnter set, or set immediately)
+// and ReturnPrevPageFunc optionally. You can store the option in gta3.set if you pass true to corresponding parameter.
+//
+// Dynamic: Passing variable to function is only needed if you want to store it, otherwise you should do
+// all the operations with ButtonPressFunc, this includes allocating the variable.
+// Left-side text is passed while creating and static, but ofc right-side text is dynamic -
+// you should return it in DrawFunc, which is called on every draw. ReturnPrevPageFunc is also here if needed.
//
-// Dynamic: Function doesn't accept value pointer, user should do operations with handling ButtonPressFunc.
-// Right-side text can be set via DrawFunc, which is called on every draw. ReturnPrevPageFunc is also here if needed.
+// Redirect: Redirection to another screen. selectedOption parameter is the highlighted option user will see after the redirection.
+//
+// Built-in action: As the name suggests, any action that game has built-in. But as an extra you can set the option text,
+// and can be informed on button press/focus loss via buttonPressFunc. ReturnPrevPageFunc is also here.
#define FEOPTION_SELECT 0
#define FEOPTION_DYNAMIC 1
#define FEOPTION_REDIRECT 2
#define FEOPTION_GOBACK 3
+#define FEOPTION_BUILTIN_ACTION 4
+// -- Returned via ButtonPressFunc() action param.
#define FEOPTION_ACTION_LEFT 0
#define FEOPTION_ACTION_RIGHT 1
#define FEOPTION_ACTION_SELECT 2
#define FEOPTION_ACTION_FOCUSLOSS 3
-void RemoveCustomFrontendOptions();
-void CustomFrontendOptionsPopulate();
+// -- Passed via FrontendScreenAdd()
+#define FESCREEN_CENTER 0
+#define FESCREEN_LEFT_ALIGN 1
+#define FESCREEN_RIGHT_ALIGN 2
-// for static and dynamic options
+// -- Callbacks
+
+// pretty much in everything I guess, and optional in all of them
typedef void (*ReturnPrevPageFunc)();
// for static options
-typedef void (*ChangeFunc)(int8 displayedValue); // called before updating the value
+typedef void (*ChangeFunc)(int8 displayedValue); // called before updating the value.
+ // only called on enter if onlyApplyOnEnter set, otherwise called on every value change
// for dynamic options
-typedef wchar* (*DrawFunc)(bool* disabled); // should return pointer to right text. *disabled = true will make it dark yellow
+typedef wchar* (*DrawFunc)(bool* disabled, bool userHovering); // you must return a pointer for right text.
+ // you can also set *disabled if you want to gray it out.
typedef void (*ButtonPressFunc)(int8 action); // see FEOPTION_ACTIONs above
+struct FrontendScreen
+{
+ int id;
+ char name[8];
+ eMenuSprites sprite;
+ int prevPage;
+ int columnWidth;
+ int headerHeight;
+ int lineHeight;
+ int8 font;
+ float fontScaleX;
+ float fontScaleY;
+ int8 alignment;
+ bool showLeftRightHelper;
+ ReturnPrevPageFunc returnPrevPageFunc;
+};
+
struct FrontendOption
{
int8 type;
int8 screenOptionOrder;
- eMenuScreen screen;
- const wchar* leftText;
+ int32 screen;
+ wchar leftText[64];
ReturnPrevPageFunc returnPrevPageFunc;
+ int8* value;
+ int8 displayedValue; // only if onlyApplyOnEnter enabled for now
+ bool save;
+ int32 ogOptionId; // for replacements, see overwrite parameter of SetCursor
union {
- // Only for dynamic
+ // Only for dynamic / built-in action
struct {
DrawFunc drawFunc;
ButtonPressFunc buttonPressFunc;
@@ -55,33 +109,54 @@ struct FrontendOption
struct {
const wchar** rightTexts;
int8 numRightTexts;
- int8 *value;
- int8 displayedValue; // if onlyApplyOnEnter enabled
bool onlyApplyOnEnter;
ChangeFunc changeFunc;
+ int8 lastSavedValue; // only if onlyApplyOnEnter enabled
};
// Only for redirect
struct {
- eMenuScreen to;
+ int to;
int8 option;
bool fadeIn;
};
};
};
+// -- Internal things
+void RemoveCustomFrontendOptions();
+void CustomFrontendOptionsPopulate();
+
+extern int lastOgScreen; // for reloading
+
extern int numCustomFrontendOptions;
extern FrontendOption* customFrontendOptions;
-// To be used in ButtonPressFunc / ChangeFunc(but that would be weird):
-void ChangeScreen(eMenuScreen screen, int option = 0, bool fadeIn = true);
+extern int numCustomFrontendScreens;
+extern FrontendScreen* customFrontendScreens;
+
+// -- To be used in ButtonPressFunc / ChangeFunc(this one would be weird):
+void ChangeScreen(int screen, int option = 0, bool fadeIn = true);
void GoBack(bool fadeIn = true);
-// If option is positive number, all calls will increase it before using it (you can think it as cursor). -1 means before the back button, -2 is end of page
-void FrontendOptionSetPosition(eMenuScreen screen, int8 option = -1);
+uint8 GetNumberOfMenuOptions(int screen);
-void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc);
-void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc rightTextDrawFunc, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc);
-void FrontendOptionAddRedirect(const wchar* text, eMenuScreen to, int8 selectedOption = 0, bool fadeIn = true);
+// -- Placing the cursor to append/overwrite option
+//
+// Done via FrontendOptionSetCursor(screen, position, overwrite = false), parameters explained below:
+// Screen: as the name suggests. Also accepts the screen IDs returned from FrontendScreenAdd.
+// Option: if positive, next AddOption call will put the option to there and progress the cursor.
+// if negative, cursor will be placed on bottom-(pos+1), so -1 means the very bottom, -2 means before the back button etc.
+// Overwrite: Use to overwrite the options, not appending a new one. AddOption calls will still progress the cursor.
+
+void FrontendOptionSetCursor(int screen, int8 option, bool overwrite = false);
+
+// var is optional in AddDynamic, you can enable save parameter if you pass one, otherwise pass nil/0
+void FrontendOptionAddBuiltinAction(const wchar* leftText, int action, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc);
+void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save = false);
+void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save = false);
+void FrontendOptionAddRedirect(const wchar* text, int to, int8 selectedOption = 0, bool fadeIn = true);
void FrontendOptionAddBackButton(const wchar* text, bool fadeIn = true);
+
+uint8 FrontendScreenAdd(char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight, int8 font, float fontScaleX, float fontScaleY, int8 alignment, bool showLeftRightHelper, ReturnPrevPageFunc returnPrevPageFunc = nil);
#endif \ No newline at end of file