Automatic menu buttons

This commit is contained in:
NyakoFox 2024-03-25 14:38:04 -03:00
parent 9353c4f20c
commit 5febfaed56
9 changed files with 214 additions and 28 deletions

View File

@ -6559,41 +6559,62 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
}
currentmenuname = t;
int buttonyoff = 0;
bool buttonscentered = false;
menuyoff = 0;
int maxspacing = 30; // maximum value for menuspacing, can only become lower.
bool auto_buttons = true;
bool auto_center = true;
menucountdown = 0;
menuoptions.clear();
touch::remove_dynamic_buttons();
switch (t)
{
case Menu::mainmenu:
{
if (ingame_titlemode)
{
/* We shouldn't be here! */
SDL_assert(0 && "Entering main menu from in-game options!");
break;
}
int offset = 0;
#if !defined(MAKEANDPLAY)
option(loc::gettext("play"));
touch::create_menu_button(80, 96, 160, 26, loc::gettext("play"), offset++);
#endif
option(loc::gettext("levels"));
option(loc::gettext("options"));
touch::create_menu_button(80, 128, 160, 26, loc::gettext("levels"), offset++);
touch::create_menu_button(164, 160, 76, 26, loc::gettext("options"), offset++);
if (loc::show_translator_menu)
{
option(loc::gettext("translator"));
offset++;
}
option(loc::gettext("credits"));
option(loc::gettext("quit"));
touch::create_menu_button(80, 160, 76, 26, loc::gettext("credits"), offset++);
touch::create_menu_button(80, 192, 160, 26, loc::gettext("quit"), offset++); // TODO: Don't show this on phones! Fine for now, but we have to do it before submitting to app stores.
menuyoff = -10;
maxspacing = 15;
auto_buttons = false;
break;
}
case Menu::playerworlds:
buttonyoff = -16;
option(loc::gettext("play a level"));
option(loc::gettext("level editor"), !editor_disabled);
if (!editor_disabled)
{
option(loc::gettext("open level folder"), FILESYSTEM_openDirectoryEnabled());
option(loc::gettext("show level folder path"));
option(loc::gettext("open level folder"), FILESYSTEM_openDirectoryEnabled(), PR_RTL_XFLIP, false);
option(loc::gettext("show level folder path"), true, PR_RTL_XFLIP, false);
}
option(loc::gettext("return"));
menuyoff = -40;
@ -6710,7 +6731,7 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
menuxoff = 20;
menuyoff = 70-(menuoptions.size()*10);
menuspacing = 5;
return; // skip automatic centering, will turn out bad with levels list
auto_center = false;
}
break;
case Menu::quickloadlevel:
@ -6749,6 +6770,8 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
option(loc::gettext("return"));
menuyoff = -10;
maxspacing = 15;
buttonscentered = true;
break;
case Menu::graphicoptions:
if (!gameScreen.isForcedFullscreen())
@ -6766,6 +6789,8 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
option(loc::gettext("return"));
menuyoff = -10;
maxspacing = 15;
buttonscentered = true;
break;
case Menu::ed_settings:
option(loc::gettext("change description"));
@ -6826,13 +6851,15 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
option(loc::gettext("gameplay"));
option(loc::gettext("graphics"));
option(loc::gettext("audio"));
option(loc::gettext("game pad"));
option(loc::gettext("game pad"), true, PR_RTL_XFLIP, false);
option(loc::gettext("touch input"));
option(loc::gettext("accessibility"));
option(loc::gettext("language"), !translator_cutscene_test);
option(loc::gettext("return"));
menuyoff = 0;
maxspacing = 15;
buttonscentered = true;
break;
case Menu::speedrunneroptions:
option(loc::gettext("glitchrunner mode"));
@ -6844,6 +6871,8 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
option(loc::gettext("return"));
menuyoff = 0;
maxspacing = 15;
buttonscentered = true;
break;
case Menu::setglitchrunner:
{
@ -6888,6 +6917,8 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
option(loc::gettext("return"));
menuyoff = 0;
maxspacing = 15;
buttonscentered = true;
break;
case Menu::controller:
option(loc::gettext("analog stick sensitivity"));
@ -7004,7 +7035,8 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
menuxoff = 20;
menuyoff = 55-(menuoptions.size()*10);
menuspacing = 5;
return; // skip automatic centering, will turn out bad with scripts list
auto_center = false;
break;
case Menu::translator_maintenance:
option(loc::gettext("sync language files"));
option(loc::gettext("global statistics"), false);
@ -7048,12 +7080,19 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
option(loc::gettext("unlock secret lab"), !unlock[Unlock_SECRETLAB]);
option(loc::gettext("return"));
menuyoff = -20;
buttonscentered = true;
break;
case Menu::credits:
option(loc::gettext("next page"));
option(loc::gettext("last page"));
option(loc::gettext("return"));
menuyoff = 64;
touch::create_menu_button(46 - 16, 200, 76, 26, loc::gettext("last"), 1);
touch::create_menu_button(122, 200, 76, 26, loc::gettext("return"), 2);
touch::create_menu_button(198 + 16, 200, 76, 26, loc::gettext("next"), 0);
auto_buttons = false;
break;
case Menu::credits2:
case Menu::credits25:
@ -7066,12 +7105,22 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
option(loc::gettext("previous page"));
option(loc::gettext("return"));
menuyoff = 64;
touch::create_menu_button(46 - 16, 200, 76, 26, loc::gettext("previous"), 1);
touch::create_menu_button(122, 200, 76, 26, loc::gettext("return"), 2);
touch::create_menu_button(198 + 16, 200, 76, 26, loc::gettext("next"), 0);
auto_buttons = false;
break;
case Menu::credits6:
option(loc::gettext("first page"));
option(loc::gettext("previous page"));
option(loc::gettext("return"));
menuyoff = 64;
touch::create_menu_button(46 - 16, 200, 76, 26, loc::gettext("previous"), 1);
touch::create_menu_button(122, 200, 76, 26, loc::gettext("return"), 2);
touch::create_menu_button(198 + 16, 200, 76, 26, loc::gettext("first"), 0);
auto_buttons = false;
break;
case Menu::play:
{
@ -7186,6 +7235,7 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
}
else
{
buttonscentered = true;
if (save_exists())
{
option(loc::gettext("continue"));
@ -7238,6 +7288,8 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
option(loc::gettext("return"));
menuyoff = 8;
maxspacing = 20;
buttonscentered = true;
break;
case Menu::intermissionmenu:
option(loc::gettext("play intermission 1"));
@ -7350,25 +7402,65 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
break;
}
// Automatically center the menu. We must check the width of the menu with the initial horizontal spacing.
// If it's too wide, reduce the horizontal spacing by 5 and retry.
// Try to limit the menu width to 272 pixels: 320 minus 16*2 for square brackets, minus 8*2 padding.
// The square brackets fall outside the menu width (i.e. selected menu options are printed 16 pixels to the left)
bool done_once = false;
int menuwidth = 0;
for (; !done_once || (menuwidth > 272 && menuspacing > 0); maxspacing -= 5)
if (auto_center)
{
done_once = true;
menuspacing = maxspacing;
menuwidth = 0;
for (size_t i = 0; i < menuoptions.size(); i++)
// Automatically center the menu. We must check the width of the menu with the initial horizontal spacing.
// If it's too wide, reduce the horizontal spacing by 5 and retry.
// Try to limit the menu width to 272 pixels: 320 minus 16*2 for square brackets, minus 8*2 padding.
// The square brackets fall outside the menu width (i.e. selected menu options are printed 16 pixels to the left)
bool done_once = false;
int menuwidth = 0;
for (; !done_once || (menuwidth > 272 && menuspacing > 0); maxspacing -= 5)
{
int width = i*menuspacing + font::len(menuoptions[i].print_flags, menuoptions[i].text);
if (width > menuwidth)
menuwidth = width;
done_once = true;
menuspacing = maxspacing;
menuwidth = 0;
for (size_t i = 0; i < menuoptions.size(); i++)
{
int width = i * menuspacing + font::len(menuoptions[i].print_flags, menuoptions[i].text);
if (width > menuwidth)
menuwidth = width;
}
}
menuxoff = (320 - menuwidth) / 2;
}
if (auto_buttons)
{
int base_y = 128 + menuyoff + buttonyoff;
if (buttonscentered)
{
int count = 0;
for (int i = 0; i < menuoptions.size(); i++)
{
if (menuoptions[i].auto_button)
{
count++;
}
}
base_y = (240 - count * 32) / 2;
}
int offset = 0;
for (int i = 0; i < (int) menuoptions.size(); i++)
{
if (menuoptions[i].auto_button)
{
touch::create_menu_button(
(320 - 160) / 2,
base_y + offset * 32,
160,
26,
menuoptions[i].text,
i,
menuoptions[i].active
);
offset++;
}
}
}
menuxoff = (320-menuwidth)/2;
}
bool Game::can_unlock_ndm(void)

View File

@ -31,6 +31,7 @@ struct MenuOption
char text[MENU_TEXT_BYTES];
bool active;
uint32_t print_flags;
bool auto_button;
};
//Menu IDs
@ -387,12 +388,13 @@ public:
int menuspacing;
std::vector<MenuStackFrame> menustack;
void inline option(const char* text, bool active = true, uint32_t print_flags = PR_RTL_XFLIP)
void inline option(const char* text, bool active = true, uint32_t print_flags = PR_RTL_XFLIP, bool auto_button = true)
{
MenuOption menuoption;
SDL_strlcpy(menuoption.text, text, sizeof(menuoption.text));
menuoption.active = active;
menuoption.print_flags = print_flags;
menuoption.auto_button = auto_button;
menuoptions.push_back(menuoption);
}

View File

@ -386,7 +386,7 @@ static void slidermodeinput(void)
*user_changing_volume = SDL_clamp(*user_changing_volume, 0, USER_VOLUME_MAX);
}
static void menuactionpress(void)
void menuactionpress(void)
{
if (game.menutestmode)
{
@ -3165,6 +3165,7 @@ void mapinput(void)
if (key.isDown(KEYBOARD_ENTER) || key.isDown(game.controllerButton_map)) game.press_map = true;
if ((key.isDown(27) || touch::button_tapped(TOUCH_BUTTON_CANCEL)) && !game.mapheld)
{
touch::remove_dynamic_buttons();
game.mapheld = true;
if (game.menupage < 9
|| (game.menupage >= 20 && game.menupage <= 21))

View File

@ -1,6 +1,8 @@
#ifndef INPUT_H
#define INPUT_H
void menuactionpress(void);
void titleinput(void);
void gameinput(void);

View File

@ -1932,7 +1932,15 @@ void titlerender(void)
if(tg>255) tg=255;
if (tb < 0) tb = 0;
if(tb>255) tb=255;
graphics.drawmenu(tr, tg, tb, game.currentmenuname);
if (key.using_touch)
{
touch::render_buttons(tr, tg, tb);
}
else
{
graphics.drawmenu(tr, tg, tb, game.currentmenuname);
}
}
graphics.drawfade();

View File

@ -6,6 +6,7 @@
#include "Enums.h"
#include "Map.h"
#include "Script.h"
#include "Touch.h"
#include "UtilityClass.h"
static inline void titleupdatetextcol(void)
@ -227,6 +228,7 @@ void maprenderfixed(void)
{
graphics.menuoffset = threshold;
//go back to gamemode!
touch::remove_dynamic_buttons();
game.mapheld = true;
game.gamestate = GAMEMODE;
graphics.resumegamemode = false;

View File

@ -2571,6 +2571,8 @@ void scriptclass::startgamemode(const enum StartMode mode)
}
}
touch::remove_dynamic_buttons();
/* Containers which need to be reset before gameplay starts
* ex. before custom levels get loaded */

View File

@ -73,6 +73,8 @@ namespace touch
void init(void)
{
scale = 10;
use_buttons = false;
textbox_style = false;
for (int i = 0; i < NUM_TOUCH_BUTTONS; i++)
{
@ -92,12 +94,82 @@ namespace touch
refresh_all_buttons();
}
TouchButton create_button(int x, int y, int width, int height, std::string text)
{
int scale = get_scale();
if (width == -1)
{
width = font::len(PR_CEN | (SDL_min((scale - 1), 7) << 0), text.c_str()) + 24 * scale;
}
if (height == -1)
{
height = font::height(PR_CEN | (SDL_min((scale - 1), 7) << 0)) + 18 * scale;
}
TouchButton button;
button.x = x;
button.y = y;
button.width = width;
button.height = height;
button.image = NULL;
button.text = text;
button.active = true;
button.core = false;
button.ui = false;
button.down = false;
button.pressed = false;
button.fingerId = -1;
button.type = TOUCH_BUTTON_TYPE_NONE;
button.id = -1;
button.disabled = false;
return button;
}
/* Helper function to create menu buttons (very common) in a single line */
void create_menu_button(int x, int y, int width, int height, std::string text, int id)
{
TouchButton button = create_button(x, y, width, height, text);
button.type = TOUCH_BUTTON_TYPE_MENU;
button.id = id;
register_button(button);
}
void create_menu_button(int x, int y, int width, int height, std::string text, int id, bool active)
{
TouchButton button = create_button(x, y, width, height, text);
button.type = TOUCH_BUTTON_TYPE_MENU;
button.id = id;
button.disabled = !active;
register_button(button);
}
void register_button(TouchButton button)
{
dynamic_buttons.push_back(button);
refresh_all_buttons();
}
void remove_dynamic_buttons(void)
{
dynamic_buttons.clear();
refresh_all_buttons();
}
void on_button_up(TouchButton* button)
{
bool version2_2 = GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2);
switch (button->type)
{
case TOUCH_BUTTON_TYPE_MENU:
game.currentmenuoption = button->id;
menuactionpress();
break;
case TOUCH_BUTTON_TYPE_NONE:
default:
break;
@ -165,12 +237,9 @@ namespace touch
break;
case TITLEMODE:
if (game.menustart)
if (!game.menustart)
{
buttons[TOUCH_BUTTON_LEFT].active = true;
buttons[TOUCH_BUTTON_RIGHT].active = true;
buttons[TOUCH_BUTTON_CANCEL].active = true;
buttons[TOUCH_BUTTON_CONFIRM].active = true;
use_buttons = false;
}
break;
case TELEPORTERMODE:

View File

@ -90,6 +90,14 @@ namespace touch
void reset(void);
void update_buttons(void);
TouchButton create_button(int x, int y, int width, int height, std::string text);
void register_button(TouchButton button);
void create_menu_button(int x, int y, int width, int height, std::string text, int id);
void create_menu_button(int x, int y, int width, int height, std::string text, int id, bool disabled);
void remove_dynamic_buttons(void);
void on_button_up(TouchButton* button);
void init(void);