From 0023c821db369733782b5a4e72574c066d112be7 Mon Sep 17 00:00:00 2001 From: Dav999-v Date: Mon, 29 Jun 2020 02:09:52 +0200 Subject: [PATCH] Make menus automatically centered and narrowed All menus had a hardcoded X position (offset to an arbitrary starting point of 110) and a hardcoded horizontal spacing for the "staircasing" (mostly 30 pixels, but for some specific menus hardcoded to 15, 20 or something else). Not all menus were centered, and seem to have been manually made narrower (with lower horizontal spacing) whenever text ran offscreen during development. This system may already be hard to work with in an English-only menu system, since you may need to adjust horizontal spacing or positioning when adding an option. The main reason I made this change is that it's even less optimal when menu options have to be translated, since maximum string lengths are hard to determine, and it's easy to have menu options running offscreen, especially when not all menus are checked for all languages and when options could be added in the middle of a menu after translations of that menu are already checked. Now, menus are automatically centered based on their options, and they are automatically made narrower if they won't fit with the default horizontal spacing of 30 pixels (with some padding). The game.menuxoff variable for the menu X position is now also offset to 0 instead of 110 The _default_ horizontal spacing can be changed on a per-menu basis, and most menus (not all) which already had a narrower spacing set, retain that as a maximum spacing, simply because they looked odd with 30 pixels of spacing (especially the main menu). They will be made even narrower automatically if needed. In the most extreme case, the spacing can go down to 0 and options will be displayed right below each other. This isn't in the usual style of the game, but at least we did the best we could to prevent options running offscreen. The only exception to automatic menu centering and narrowing is the list of player levels, because it's a special case and existing behavior would be better than automatic centering there. --- desktop_version/src/Game.cpp | 73 +++++++++++++------------------- desktop_version/src/Game.h | 1 + desktop_version/src/Graphics.cpp | 28 ++++++------ desktop_version/src/Graphics.h | 4 +- desktop_version/src/Render.cpp | 24 +---------- desktop_version/src/editor.cpp | 2 +- 6 files changed, 50 insertions(+), 82 deletions(-) diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp index 75699a49..ad65a72a 100644 --- a/desktop_version/src/Game.cpp +++ b/desktop_version/src/Game.cpp @@ -6958,8 +6958,8 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) currentmenuoption = 0; currentmenuname = t; - menuxoff = 0; menuyoff = 0; + int maxspacing = 30; // maximum value for menuspacing, can only become lower. menucountdown = 0; menuoptions.clear(); @@ -6978,8 +6978,8 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("view credits"); #endif option("quit game"); - menuxoff = -16; menuyoff = -10; + maxspacing = 15; break; #if !defined(NO_CUSTOM_LEVELS) case Menu::playerworlds: @@ -6989,14 +6989,13 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) #endif option("open level folder", FILESYSTEM_openDirectoryEnabled()); option("back to menu"); - menuxoff = -30; menuyoff = -40; + maxspacing = 15; break; case Menu::levellist: if(ed.ListOfMetaData.size()==0) { option("ok"); - menuxoff = 0; menuyoff = -20; } else @@ -7057,8 +7056,10 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) } option("return to menu"); - menuxoff = -90; + menuxoff = 20; menuyoff = 70-(menuoptions.size()*10); + menuspacing = 5; + return; // skip automatic centering, will turn out bad with levels list } break; #endif @@ -7066,18 +7067,15 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("continue from save"); option("start from beginning"); option("back to levels"); - menuxoff = -40; menuyoff = -30; break; case Menu::youwannaquit: option("yes, quit"); option("no, return"); - menuxoff = 0; menuyoff = -20; break; case Menu::errornostart: option("ok"); - menuxoff = 0; menuyoff = -20; break; case Menu::graphicoptions: @@ -7089,7 +7087,6 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("toggle fps"); option("toggle vsync"); option("return"); - menuxoff = -85; menuyoff = 0; break; case Menu::ed_settings: @@ -7101,8 +7098,8 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("save level"); option("quit to main menu"); - menuxoff = -46; menuyoff = -20; + maxspacing = 15; break; case Menu::ed_desc: option("change name"); @@ -7111,21 +7108,21 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("change website"); option("back to settings"); - menuxoff = -40; menuyoff = 6; + maxspacing = 15; break; case Menu::ed_music: option("next song"); option("back"); - menuxoff = -10; menuyoff = 16; + maxspacing = 15; break; case Menu::ed_quit: option("yes, save and quit"); option("no, quit without saving"); option("return to editor"); - menuxoff = -50; menuyoff = 8; + maxspacing = 15; break; case Menu::options: option("accessibility options"); @@ -7140,7 +7137,6 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) } option("return"); - menuxoff = -40; menuyoff = 0; break; case Menu::accessibility: @@ -7152,7 +7148,6 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("load screen"); option("room name bg"); option("return"); - menuxoff = -85; menuyoff = -10; break; case Menu::controller: @@ -7161,19 +7156,16 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("bind enter"); option("bind menu"); option("return"); - menuxoff = -40; menuyoff = 10; break; case Menu::cleardatamenu: option("no! don't delete"); option("yes, delete everything"); - menuxoff = -30; menuyoff = 64; break; case Menu::setinvincibility: option("no, return to options"); option("yes, enable"); - menuxoff = -30; menuyoff = 64; break; case Menu::setslowdown: @@ -7181,7 +7173,6 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("80% speed"); option("60% speed"); option("40% speed"); - menuxoff = -40; menuyoff = 16; break; case Menu::unlockmenu: @@ -7192,56 +7183,48 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("unlock ship jukebox", (stat_trinkets<20)); option("unlock secret lab", !unlock[8]); option("return"); - menuxoff = -70; menuyoff = -20; break; case Menu::credits: option("next page"); option("last page"); option("return"); - menuxoff = 20; menuyoff = 64; break; case Menu::credits2: option("next page"); option("previous page"); option("return"); - menuxoff = 20; menuyoff = 64; break; case Menu::credits25: option("next page"); option("previous page"); option("return"); - menuxoff = 20; menuyoff = 64; break; case Menu::credits3: option("next page"); option("previous page"); option("return"); - menuxoff = 20; menuyoff = 64; break; case Menu::credits4: option("next page"); option("previous page"); option("return"); - menuxoff = 20; menuyoff = 64; break; case Menu::credits5: option("next page"); option("previous page"); option("return"); - menuxoff = 20; menuyoff = 64; break; case Menu::credits6: option("first page"); option("previous page"); option("return"); - menuxoff = 20; menuyoff = 64; break; case Menu::play: @@ -7357,12 +7340,10 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("return"); if (unlock[8]) { - menuxoff = -40; menuyoff = -30; } else { - menuxoff = -20; menuyoff = -40; } } @@ -7375,13 +7356,11 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) case Menu::unlockintermission: case Menu::unlockflipmode: option("continue"); - menuxoff = 20; menuyoff = 70; break; case Menu::newgamewarning: option("start new game"); option("return to menu"); - menuxoff = -30; menuyoff = 64; break; case Menu::playmodes: @@ -7390,14 +7369,13 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("no death mode", unlock[17] && !map.invincibility && slowdown == 30); option("flip mode", unlock[18]); option("return to play menu"); - menuxoff = -70; menuyoff = 8; + maxspacing = 20; break; case Menu::intermissionmenu: option("play intermission 1"); option("play intermission 2"); option("return to play menu"); - menuxoff = -50; menuyoff = -35; break; case Menu::playint1: @@ -7406,7 +7384,6 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("Verdigris"); option("Victoria"); option("return"); - menuxoff = -60; menuyoff = 10; break; case Menu::playint2: @@ -7415,7 +7392,6 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("Verdigris"); option("Victoria"); option("return"); - menuxoff = -60; menuyoff = 10; break; case Menu::continuemenu: @@ -7423,14 +7399,12 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("continue from teleporter"); option("continue from quicksave"); option("return to play menu"); - menuxoff = -60; menuyoff = 20; break; case Menu::startnodeathmode: option("disable cutscenes"); option("enable cutscenes"); option("return to play menu"); - menuxoff = -60; menuyoff = 40; break; case Menu::gameover: @@ -7439,7 +7413,6 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) break; case Menu::gameover2: option("return to play menu"); - menuxoff = -25; menuyoff = 80; break; case Menu::unlockmenutrials: @@ -7451,7 +7424,6 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("the final level", !unlock[14]); option("return to unlock menu"); - menuxoff = -80; menuyoff = 0; break; case Menu::timetrials: @@ -7463,8 +7435,8 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option(unlock[14] ? "the final level" : "???", unlock[14]); option("return to play menu"); - menuxoff = -80; menuyoff = 0; + maxspacing = 15; break; case Menu::nodeathmodecomplete: menucountdown = 90; @@ -7472,7 +7444,6 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) break; case Menu::nodeathmodecomplete2: option("return to play menu"); - menuxoff = -25; menuyoff = 70; break; case Menu::timetrialcomplete: @@ -7486,15 +7457,31 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) case Menu::timetrialcomplete3: option("return to play menu"); option("try again"); - menuxoff = -25; menuyoff = 70; break; case Menu::gamecompletecontinue: option("return to play menu"); - menuxoff = -25; menuyoff = 70; break; } + + // Automatically center the menu. We must check the width of the menu with the initial horizontal spacing. + // If it doesn't fit onscreen (including square brackets), reduce the horizontal spacing by 5 and retry. + bool done_once = false; + int menuwidth = 0; + for (; !done_once || (menuwidth > 272 && maxspacing > 0); maxspacing -= 5) + { + done_once = true; + menuspacing = maxspacing; + menuwidth = 0; + for (size_t i = 0; i < menuoptions.size(); i++) + { + int width = i*menuspacing + graphics.len(menuoptions[i].text); + if (width > menuwidth) + menuwidth = width; + } + } + menuxoff = (320-menuwidth)/2; } void Game::deletequick() diff --git a/desktop_version/src/Game.h b/desktop_version/src/Game.h index 0b431c3c..06f3b813 100644 --- a/desktop_version/src/Game.h +++ b/desktop_version/src/Game.h @@ -218,6 +218,7 @@ public: enum Menu::MenuName kludge_ingametemp; int current_credits_list_index; int menuxoff, menuyoff; + int menuspacing; std::vector menustack; void inline option(std::string text, bool active = true) diff --git a/desktop_version/src/Graphics.cpp b/desktop_version/src/Graphics.cpp index cde449e1..140b6763 100644 --- a/desktop_version/src/Graphics.cpp +++ b/desktop_version/src/Graphics.cpp @@ -1242,7 +1242,7 @@ void Graphics::processfade() } } -void Graphics::drawmenu( int cr, int cg, int cb, int division /*= 30*/ ) +void Graphics::drawmenu( int cr, int cg, int cb ) { for (size_t i = 0; i < game.menuoptions.size(); i++) { @@ -1254,14 +1254,14 @@ void Graphics::drawmenu( int cr, int cg, int cb, int division /*= 30*/ ) std::string tempstring = game.menuoptions[i].text; std::transform(tempstring.begin(), tempstring.end(),tempstring.begin(), ::toupper); tempstring = std::string("[ ") + tempstring + std::string(" ]"); - Print(110 + (i * division) - 16 +game.menuxoff, 140 + (i * 12) +game.menuyoff, tempstring, cr, cg, cb); + Print((i * game.menuspacing) - 16 +game.menuxoff, 140 + (i * 12) +game.menuyoff, tempstring, cr, cg, cb); } else { std::string tempstring = game.menuoptions[i].text; tempstring = "[ " + tempstring + " ]"; //Draw it in gray - Print(110 + (i * division) - 16 +game.menuxoff, 140 + (i * 12)+game.menuyoff, tempstring, 128, 128, 128); + Print((i * game.menuspacing) - 16 +game.menuxoff, 140 + (i * 12)+game.menuyoff, tempstring, 128, 128, 128); } } else @@ -1269,18 +1269,18 @@ void Graphics::drawmenu( int cr, int cg, int cb, int division /*= 30*/ ) //Draw it normally if (game.menuoptions[i].active) { - Print(110 + (i * division) +game.menuxoff, 140 + (i * 12)+game.menuyoff, game.menuoptions[i].text, cr, cg, cb); + Print((i * game.menuspacing) +game.menuxoff, 140 + (i * 12)+game.menuyoff, game.menuoptions[i].text, cr, cg, cb); } else { //Draw it in gray - Print(110 + (i * division) +game.menuxoff, 140 + (i * 12)+game.menuyoff, game.menuoptions[i].text, 128, 128, 128); + Print((i * game.menuspacing) +game.menuxoff, 140 + (i * 12)+game.menuyoff, game.menuoptions[i].text, 128, 128, 128); } } } } -void Graphics::drawlevelmenu( int cr, int cg, int cb, int division /*= 30*/ ) +void Graphics::drawlevelmenu( int cr, int cg, int cb ) { for (size_t i = 0; i < game.menuoptions.size(); i++) { @@ -1293,14 +1293,14 @@ void Graphics::drawlevelmenu( int cr, int cg, int cb, int division /*= 30*/ ) std::string tempstring = game.menuoptions[i].text; std::transform(tempstring.begin(), tempstring.end(),tempstring.begin(), ::toupper); tempstring = std::string("[ ") + tempstring + std::string(" ]"); - Print(110 + (i * division) - 16 +game.menuxoff, 140+8 + (i * 12) +game.menuyoff, tempstring, cr, cg, cb); + Print((i * game.menuspacing) - 16 +game.menuxoff, 140+8 + (i * 12) +game.menuyoff, tempstring, cr, cg, cb); } else { std::string tempstring = game.menuoptions[i].text; tempstring = "[ " + tempstring + " ]"; //Draw it in gray - Print(110 + (i * division) - 16 +game.menuxoff, 140+8 + (i * 12)+game.menuyoff, tempstring, 128, 128, 128); + Print((i * game.menuspacing) - 16 +game.menuxoff, 140+8 + (i * 12)+game.menuyoff, tempstring, 128, 128, 128); } }else{ //Draw it highlighted @@ -1309,14 +1309,14 @@ void Graphics::drawlevelmenu( int cr, int cg, int cb, int division /*= 30*/ ) std::string tempstring = game.menuoptions[i].text; std::transform(tempstring.begin(), tempstring.end(),tempstring.begin(), ::toupper); tempstring = std::string("[ ") + tempstring + std::string(" ]"); - Print(110 + (i * division) - 16 +game.menuxoff, 144 + (i * 12) +game.menuyoff, tempstring, cr, cg, cb); + Print((i * game.menuspacing) - 16 +game.menuxoff, 144 + (i * 12) +game.menuyoff, tempstring, cr, cg, cb); } else { std::string tempstring = game.menuoptions[i].text; tempstring = "[ " + tempstring + " ]"; //Draw it in gray - Print(110 + (i * division) - 16 +game.menuxoff, 144 + (i * 12)+game.menuyoff, tempstring, 128, 128, 128); + Print((i * game.menuspacing) - 16 +game.menuxoff, 144 + (i * 12)+game.menuyoff, tempstring, 128, 128, 128); } } } @@ -1326,23 +1326,23 @@ void Graphics::drawlevelmenu( int cr, int cg, int cb, int division /*= 30*/ ) //Draw it normally if (game.menuoptions[i].active) { - Print(110 + (i * division) +game.menuxoff, 140+8 + (i * 12)+game.menuyoff, game.menuoptions[i].text, cr, cg, cb); + Print((i * game.menuspacing) +game.menuxoff, 140+8 + (i * 12)+game.menuyoff, game.menuoptions[i].text, cr, cg, cb); } else { //Draw it in gray - Print(110 + (i * division) +game.menuxoff, 140+8 + (i * 12)+game.menuyoff, game.menuoptions[i].text, 128, 128, 128); + Print((i * game.menuspacing) +game.menuxoff, 140+8 + (i * 12)+game.menuyoff, game.menuoptions[i].text, 128, 128, 128); } }else{ //Draw it normally if (game.menuoptions[i].active) { - Print(110 + (i * division) +game.menuxoff, 144 + (i * 12)+game.menuyoff, game.menuoptions[i].text, cr, cg, cb); + Print((i * game.menuspacing) +game.menuxoff, 144 + (i * 12)+game.menuyoff, game.menuoptions[i].text, cr, cg, cb); } else { //Draw it in gray - Print(110 + (i * division) +game.menuxoff, 144 + (i * 12)+game.menuyoff, game.menuoptions[i].text, 128, 128, 128); + Print((i * game.menuspacing) +game.menuxoff, 144 + (i * 12)+game.menuyoff, game.menuoptions[i].text, 128, 128, 128); } } } diff --git a/desktop_version/src/Graphics.h b/desktop_version/src/Graphics.h index dfa01ab8..dcbde730 100644 --- a/desktop_version/src/Graphics.h +++ b/desktop_version/src/Graphics.h @@ -46,8 +46,8 @@ public: void drawcoloredtile(int x, int y, int t, int r, int g, int b); - void drawmenu(int cr, int cg, int cb, int division = 30); - void drawlevelmenu(int cr, int cg, int cb, int division = 30); + void drawmenu(int cr, int cg, int cb); + void drawlevelmenu(int cr, int cg, int cb); void processfade(); diff --git a/desktop_version/src/Render.cpp b/desktop_version/src/Render.cpp index f272f99f..ae935c69 100644 --- a/desktop_version/src/Render.cpp +++ b/desktop_version/src/Render.cpp @@ -1103,29 +1103,9 @@ void titlerender() if(tg>255) tg=255; if (tb < 0) tb = 0; if(tb>255) tb=255; - if (game.currentmenuname == Menu::timetrials || game.currentmenuname == Menu::unlockmenutrials) + if (game.currentmenuname == Menu::levellist) { - graphics.drawmenu(tr, tg, tb, 15); - } - else if (game.currentmenuname == Menu::unlockmenu) - { - graphics.drawmenu(tr, tg, tb, 15); - } - else if (game.currentmenuname == Menu::playmodes) - { - graphics.drawmenu(tr, tg, tb, 20); - } - else if (game.currentmenuname == Menu::mainmenu) - { - graphics.drawmenu(tr, tg, tb, 15); - } - else if (game.currentmenuname == Menu::playerworlds) - { - graphics.drawmenu(tr, tg, tb, 15); - } - else if (game.currentmenuname == Menu::levellist) - { - graphics.drawlevelmenu(tr, tg, tb, 5); + graphics.drawlevelmenu(tr, tg, tb); } else { diff --git a/desktop_version/src/editor.cpp b/desktop_version/src/editor.cpp index f74fc897..92cb8f09 100644 --- a/desktop_version/src/editor.cpp +++ b/desktop_version/src/editor.cpp @@ -3143,7 +3143,7 @@ void editorrender() if(tb>255) tb=255; editormenurender(tr, tg, tb); - graphics.drawmenu(tr, tg, tb, 15); + graphics.drawmenu(tr, tg, tb); } else if(ed.scripttextmod) {