Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui): Keyboard Navigation for Preference & Plugin Panels #9581

Merged
merged 10 commits into from
Dec 15, 2023
299 changes: 208 additions & 91 deletions source/PreferencesPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ this program. If not, see <https://www.gnu.org/licenses/>.
#include <SDL2/SDL.h>

#include <algorithm>
#include <string>
Koranir marked this conversation as resolved.
Show resolved Hide resolved

using namespace std;

Expand Down Expand Up @@ -155,25 +156,34 @@ bool PreferencesPanel::KeyDown(SDL_Keycode key, Uint16 mod, const Command &comma
return true;
}

if(key == SDLK_DOWN && static_cast<unsigned>(selected + 1) < zones.size())
++selected;
else if(key == SDLK_UP && selected > 0)
--selected;
if(key == SDLK_DOWN)
HandleDown();
else if(key == SDLK_UP)
HandleUp();
else if(key == SDLK_RETURN)
editing = selected;
HandleConfirm();
else if(key == 'b' || command.Has(Command::MENU) || (key == 'w' && (mod & (KMOD_CTRL | KMOD_GUI))))
Exit();
else if(key == 'c' || key == 's' || key == 'p')
{
page = key;
hoverItem.clear();
selected = 0;
}
else if(key == 'o' && page == 'p')
Files::OpenUserPluginFolder();
else if((key == 'n' || key == SDLK_PAGEUP) && currentSettingsPage < SETTINGS_PAGE_COUNT - 1)
{
++currentSettingsPage;
selected = 0;
selectedItem.clear();
}
else if((key == 'r' || key == SDLK_PAGEDOWN) && currentSettingsPage > 0)
{
--currentSettingsPage;
selected = 0;
selectedItem.clear();
}
else if((key == 'x' || key == SDLK_DELETE) && (page == 'c'))
{
if(zones[latest].Value().KeyName() != Command::MENU.KeyName())
Expand Down Expand Up @@ -205,91 +215,7 @@ bool PreferencesPanel::Click(int x, int y, int clicks)

for(const auto &zone : prefZones)
if(zone.Contains(point))
{
// For some settings, clicking the option does more than just toggle a
// boolean state keyed by the option's name.
if(zone.Value() == ZOOM_FACTOR)
{
int newZoom = Screen::UserZoom() + ZOOM_FACTOR_INCREMENT;
Screen::SetZoom(newZoom);
if(newZoom > ZOOM_FACTOR_MAX || Screen::Zoom() != newZoom)
{
// Notify the user why setting the zoom any higher isn't permitted.
// Only show this if it's not possible to zoom the view at all, as
// otherwise the dialog will show every time, which is annoying.
if(newZoom == ZOOM_FACTOR_MIN + ZOOM_FACTOR_INCREMENT)
GetUI()->Push(new Dialog(
"Your screen resolution is too low to support a zoom level above 100%."));
Screen::SetZoom(ZOOM_FACTOR_MIN);
}
// Convert to raw window coordinates, at the new zoom level.
point *= Screen::Zoom() / 100.;
point += .5 * Point(Screen::RawWidth(), Screen::RawHeight());
SDL_WarpMouseInWindow(nullptr, point.X(), point.Y());
}
else if(zone.Value() == BOARDING_PRIORITY)
Preferences::ToggleBoarding();
else if(zone.Value() == BACKGROUND_PARALLAX)
Preferences::ToggleParallax();
else if(zone.Value() == EXTENDED_JUMP_EFFECTS)
Preferences::ToggleExtendedJumpEffects();
else if(zone.Value() == VIEW_ZOOM_FACTOR)
{
// Increase the zoom factor unless it is at the maximum. In that
// case, cycle around to the lowest zoom factor.
if(!Preferences::ZoomViewIn())
while(Preferences::ZoomViewOut()) {}
}
else if(zone.Value() == SCREEN_MODE_SETTING)
Preferences::ToggleScreenMode();
else if(zone.Value() == VSYNC_SETTING)
{
if(!Preferences::ToggleVSync())
GetUI()->Push(new Dialog(
"Unable to change VSync state. (Your system's graphics settings may be controlling it instead.)"));
}
else if(zone.Value() == STATUS_OVERLAYS_ALL)
Preferences::CycleStatusOverlays(Preferences::OverlayType::ALL);
else if(zone.Value() == STATUS_OVERLAYS_FLAGSHIP)
Preferences::CycleStatusOverlays(Preferences::OverlayType::FLAGSHIP);
else if(zone.Value() == STATUS_OVERLAYS_ESCORT)
Preferences::CycleStatusOverlays(Preferences::OverlayType::ESCORT);
else if(zone.Value() == STATUS_OVERLAYS_ENEMY)
Preferences::CycleStatusOverlays(Preferences::OverlayType::ENEMY);
else if(zone.Value() == STATUS_OVERLAYS_NEUTRAL)
Preferences::CycleStatusOverlays(Preferences::OverlayType::NEUTRAL);
else if(zone.Value() == AUTO_AIM_SETTING)
Preferences::ToggleAutoAim();
else if(zone.Value() == AUTO_FIRE_SETTING)
Preferences::ToggleAutoFire();
else if(zone.Value() == EXPEND_AMMO)
Preferences::ToggleAmmoUsage();
else if(zone.Value() == FLOTSAM_SETTING)
Preferences::ToggleFlotsam();
else if(zone.Value() == TURRET_TRACKING)
Preferences::Set(FOCUS_PREFERENCE, !Preferences::Has(FOCUS_PREFERENCE));
else if(zone.Value() == REACTIVATE_HELP)
{
for(const auto &it : GameData::HelpTemplates())
Preferences::Set("help: " + it.first, false);
}
else if(zone.Value() == SCROLL_SPEED)
{
// Toggle between three different speeds.
int speed = Preferences::ScrollSpeed() + 20;
if(speed > 60)
speed = 20;
Preferences::SetScrollSpeed(speed);
}
else if(zone.Value() == DATE_FORMAT)
Preferences::ToggleDateFormat();
else if(zone.Value() == ALERT_INDICATOR)
Preferences::ToggleAlert();
// All other options are handled by just toggling the boolean state.
else
Preferences::Set(zone.Value(), !Preferences::Has(zone.Value()));
break;
}
HandleSettingsString(zone.Value(), point);
Koranir marked this conversation as resolved.
Show resolved Hide resolved

for(const auto &zone : pluginZones)
if(zone.Contains(point))
Expand Down Expand Up @@ -489,7 +415,8 @@ void PreferencesPanel::DrawControls()
bool isHovering = (index == hover && !isEditing);
if(!isHovering && index == selected)
{
table.SetHighlight(-120, 54);
auto textWidth = FontSet::Get(14).Width(command.Description());
table.SetHighlight(-120, textWidth - 110);
Koranir marked this conversation as resolved.
Show resolved Hide resolved
table.DrawHighlight(back);
}

Expand Down Expand Up @@ -539,6 +466,17 @@ void PreferencesPanel::DrawSettings()
int firstY = -248;
table.DrawAt(Point(-130, firstY));

if(hoverItem != oldHoverItem)
{
latestItem = hoverItem;
oldHoverItem = latestItem;
}
if(selectedItem != oldSelectedItem)
{
latestItem = selectedItem;
oldSelectedItem = latestItem;
}
Koranir marked this conversation as resolved.
Show resolved Hide resolved

// About SETTINGS pagination
// * An empty string indicates that a category has ended.
// * A '\t' character indicates that the first column on this page has
Expand Down Expand Up @@ -807,10 +745,23 @@ void PreferencesPanel::DrawSettings()
text = isOn ? "on" : "off";

if(setting == hoverItem)
{
table.SetHighlight(-120, 120);
table.DrawHighlight(back);
}
Koranir marked this conversation as resolved.
Show resolved Hide resolved
else if(setting == selectedItem)
{
auto width = FontSet::Get(14).Width(setting);
table.SetHighlight(-120, width - 110);
table.DrawHighlight(back);
}

table.Draw(setting, isOn ? medium : dim);
table.Draw(text, isOn ? bright : medium);
}

if(selectedItem.empty())
Koranir marked this conversation as resolved.
Show resolved Hide resolved
selectedItem = prefZones.at(selected).Value();
}


Expand Down Expand Up @@ -932,3 +883,169 @@ void PreferencesPanel::Exit()

GetUI()->Pop(this);
}



void PreferencesPanel::HandleSettingsString(const string &str, Point cursorPosition)
{
// For some settings, clicking the option does more than just toggle a
// boolean state keyed by the option's name.
if(str == ZOOM_FACTOR)
{
int newZoom = Screen::UserZoom() + ZOOM_FACTOR_INCREMENT;
Screen::SetZoom(newZoom);
if(newZoom > ZOOM_FACTOR_MAX || Screen::Zoom() != newZoom)
{
// Notify the user why setting the zoom any higher isn't permitted.
// Only show this if it's not possible to zoom the view at all, as
// otherwise the dialog will show every time, which is annoying.
if(newZoom == ZOOM_FACTOR_MIN + ZOOM_FACTOR_INCREMENT)
GetUI()->Push(new Dialog(
"Your screen resolution is too low to support a zoom level above 100%."));
Screen::SetZoom(ZOOM_FACTOR_MIN);
}
// Convert to raw window coordinates, at the new zoom level.
cursorPosition *= Screen::Zoom() / 100.;
cursorPosition += .5 * Point(Screen::RawWidth(), Screen::RawHeight());
SDL_WarpMouseInWindow(nullptr, cursorPosition.X(), cursorPosition.Y());
}
else if(str == BOARDING_PRIORITY)
Preferences::ToggleBoarding();
else if(str == BACKGROUND_PARALLAX)
Preferences::ToggleParallax();
else if(str == EXTENDED_JUMP_EFFECTS)
Preferences::ToggleExtendedJumpEffects();
else if(str == VIEW_ZOOM_FACTOR)
{
// Increase the zoom factor unless it is at the maximum. In that
// case, cycle around to the lowest zoom factor.
if(!Preferences::ZoomViewIn())
while(Preferences::ZoomViewOut()) {}
}
else if(str == SCREEN_MODE_SETTING)
Preferences::ToggleScreenMode();
else if(str == VSYNC_SETTING)
{
if(!Preferences::ToggleVSync())
GetUI()->Push(new Dialog(
"Unable to change VSync state. (Your system's graphics settings may be controlling it instead.)"));
}
else if(str == STATUS_OVERLAYS_ALL)
Preferences::CycleStatusOverlays(Preferences::OverlayType::ALL);
else if(str == STATUS_OVERLAYS_FLAGSHIP)
Preferences::CycleStatusOverlays(Preferences::OverlayType::FLAGSHIP);
else if(str == STATUS_OVERLAYS_ESCORT)
Preferences::CycleStatusOverlays(Preferences::OverlayType::ESCORT);
else if(str == STATUS_OVERLAYS_ENEMY)
Preferences::CycleStatusOverlays(Preferences::OverlayType::ENEMY);
else if(str == STATUS_OVERLAYS_NEUTRAL)
Preferences::CycleStatusOverlays(Preferences::OverlayType::NEUTRAL);
else if(str == AUTO_AIM_SETTING)
Preferences::ToggleAutoAim();
else if(str == AUTO_FIRE_SETTING)
Preferences::ToggleAutoFire();
else if(str == EXPEND_AMMO)
Preferences::ToggleAmmoUsage();
else if(str == FLOTSAM_SETTING)
Preferences::ToggleFlotsam();
else if(str == TURRET_TRACKING)
Preferences::Set(FOCUS_PREFERENCE, !Preferences::Has(FOCUS_PREFERENCE));
else if(str == REACTIVATE_HELP)
{
for(const auto &it : GameData::HelpTemplates())
Preferences::Set("help: " + it.first, false);
}
else if(str == SCROLL_SPEED)
{
// Toggle between three different speeds.
int speed = Preferences::ScrollSpeed() + 20;
if(speed > 60)
speed = 20;
Preferences::SetScrollSpeed(speed);
}
else if(str == DATE_FORMAT)
Preferences::ToggleDateFormat();
else if(str == ALERT_INDICATOR)
Preferences::ToggleAlert();
// All other options are handled by just toggling the boolean state.
else
Preferences::Set(str, !Preferences::Has(str));
}



void PreferencesPanel::HandleUp()
{
switch(page)
{
case 'c':
if(selected > 0)
--selected;
break;
case 's':
if(static_cast<unsigned>(selected) >= prefZones.size())
selected = prefZones.size() - 1;
if(selected > 0)
--selected;
selectedItem = prefZones.at(selected).Value();
break;
case 'p':
if(static_cast<unsigned>(selected) >= pluginZones.size())
selected = pluginZones.size() - 1;
if(selected > 0)
--selected;
selectedPlugin = pluginZones.at(selected).Value();
break;
default:
break;
}
}



void PreferencesPanel::HandleDown()
{
switch(page)
{
case 'c':
if(static_cast<unsigned>(selected + 1) < zones.size())
selected++;
break;
case 's':
if(static_cast<unsigned>(selected) >= prefZones.size())
selected = prefZones.size() - 1;
if(static_cast<unsigned>(selected + 1) < prefZones.size())
selected++;
Koranir marked this conversation as resolved.
Show resolved Hide resolved
selectedItem = prefZones.at(selected).Value();
break;
case 'p':
if(static_cast<unsigned>(selected) >= pluginZones.size())
selected = pluginZones.size() - 1;
if(static_cast<unsigned>(selected + 1) < pluginZones.size())
selected++;
selectedPlugin = pluginZones.at(selected).Value();
break;
default:
break;
}
}



void PreferencesPanel::HandleConfirm()
{
switch(page)
{
case 'c':
editing = selected;
break;
case 's':
HandleSettingsString(selectedItem, Screen::Dimensions() / 2.);
break;
case 'p':
Plugins::TogglePlugin(selectedPlugin);
break;
default:
break;
}
}
10 changes: 10 additions & 0 deletions source/PreferencesPanel.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ class PreferencesPanel : public Panel {

void Exit();

void HandleSettingsString(const std::string &str, Point cursorPosition);
Koranir marked this conversation as resolved.
Show resolved Hide resolved

void HandleUp();
void HandleDown();
void HandleConfirm();


private:
int editing;
Expand All @@ -69,7 +75,11 @@ class PreferencesPanel : public Panel {

Point hoverPoint;
int hoverCount = 0;
std::string selectedItem;
std::string hoverItem;
std::string oldSelectedItem;
std::string oldHoverItem;
Koranir marked this conversation as resolved.
Show resolved Hide resolved
std::string latestItem;
std::string tooltip;
WrappedText hoverText;

Expand Down
Loading