Skip to content

Commit

Permalink
Merge pull request #58142 from dseguin/main_menu_overhaul2
Browse files Browse the repository at this point in the history
Main menu overhaul (Part 1.5): mouse control fixes & improvements
  • Loading branch information
kevingranade committed Jun 10, 2022
2 parents 84e6579 + 8c9f955 commit 1e56d2a
Show file tree
Hide file tree
Showing 14 changed files with 584 additions and 103 deletions.
77 changes: 74 additions & 3 deletions data/raw/keybindings.json
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,34 @@
"name": "Move to previous category tab",
"bindings": [ { "input_method": "keyboard_char", "key": "<" }, { "input_method": "keyboard_code", "key": ",", "mod": [ "shift" ] } ]
},
{
"type": "keybinding",
"id": "QUIT",
"category": "MODMANAGER_DIALOG",
"name": "Quit",
"bindings": [
{ "input_method": "keyboard_any", "key": "ESC" },
{ "input_method": "keyboard_any", "key": "q" },
{ "input_method": "keyboard_char", "key": "Q" },
{ "input_method": "keyboard_code", "key": "q", "mod": [ "shift" ] },
{ "input_method": "keyboard_any", "key": "SPACE" },
{ "input_method": "mouse", "key": "MOUSE_RIGHT" }
]
},
{
"type": "keybinding",
"id": "QUIT",
"category": "OPTIONS",
"name": "Quit",
"bindings": [
{ "input_method": "keyboard_any", "key": "ESC" },
{ "input_method": "keyboard_any", "key": "q" },
{ "input_method": "keyboard_char", "key": "Q" },
{ "input_method": "keyboard_code", "key": "q", "mod": [ "shift" ] },
{ "input_method": "keyboard_any", "key": "SPACE" },
{ "input_method": "mouse", "key": "MOUSE_RIGHT" }
]
},
{
"type": "keybinding",
"id": "PICK_RANDOM_WORLDNAME",
Expand All @@ -838,11 +866,40 @@
},
{
"type": "keybinding",
"id": "QUIT",
"//": "Use a prefix here to avoid falling back to QUIT. Otherwise MOUSE_RIGHT is dropped when keyboard_mode is keychar.",
"id": "WORLDGEN_CONFIRM.QUIT",
"category": "WORLDGEN_CONFIRM_DIALOG",
"name": "Exit worldgen screen",
"//": "separate entry, because the global entry also has 'q' and 'Q' listed, which conflicts with the world name entry feature of this dialog",
"bindings": [ { "input_method": "keyboard_any", "key": "ESC" } ]
"//2": "separate entry, because the global entry also has 'q' and 'Q' listed, which conflicts with the world name entry feature of this dialog",
"bindings": [ { "input_method": "keyboard_any", "key": "ESC" }, { "input_method": "mouse", "key": "MOUSE_RIGHT" } ]
},
{
"type": "keybinding",
"id": "QUIT",
"category": "DISPLAY_HELP",
"name": "Quit",
"bindings": [
{ "input_method": "keyboard_any", "key": "ESC" },
{ "input_method": "keyboard_any", "key": "q" },
{ "input_method": "keyboard_char", "key": "Q" },
{ "input_method": "keyboard_code", "key": "q", "mod": [ "shift" ] },
{ "input_method": "keyboard_any", "key": "SPACE" },
{ "input_method": "mouse", "key": "MOUSE_RIGHT" }
]
},
{
"type": "keybinding",
"id": "QUIT",
"category": "SCROLLABLE_TEXT",
"name": "Quit",
"bindings": [
{ "input_method": "keyboard_any", "key": "ESC" },
{ "input_method": "keyboard_any", "key": "q" },
{ "input_method": "keyboard_char", "key": "Q" },
{ "input_method": "keyboard_code", "key": "q", "mod": [ "shift" ] },
{ "input_method": "keyboard_any", "key": "SPACE" },
{ "input_method": "mouse", "key": "MOUSE_RIGHT" }
]
},
{
"type": "keybinding",
Expand Down Expand Up @@ -1158,6 +1215,20 @@
"name": "Mouse move",
"bindings": [ { "input_method": "mouse", "key": "MOUSE_MOVE" } ]
},
{
"type": "keybinding",
"id": "QUIT",
"category": "PICK_WORLD_DIALOG",
"name": "Quit",
"bindings": [
{ "input_method": "keyboard_any", "key": "ESC" },
{ "input_method": "keyboard_any", "key": "q" },
{ "input_method": "keyboard_char", "key": "Q" },
{ "input_method": "keyboard_code", "key": "q", "mod": [ "shift" ] },
{ "input_method": "keyboard_any", "key": "SPACE" },
{ "input_method": "mouse", "key": "MOUSE_RIGHT" }
]
},
{
"type": "keybinding",
"id": "NEXT_TAB",
Expand Down
36 changes: 36 additions & 0 deletions src/cuboid_rectangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,42 @@ Tripoint clamp( const Tripoint &p, const inclusive_cuboid<Tripoint> &c )
clamp( Traits::z( p ), Traits::z( c.p_min ), Traits::z( c.p_max ) ) );
}

template<typename Index, typename Point>
int run_for_point_in( const std::map<Index, half_open_rectangle<Point>> &m, const Point &p,
const std::function<void( const std::pair<Index, half_open_rectangle<Point>> & )> &func,
bool first_only = true )
{
int cnt = 0;
for( const std::pair<const Index, half_open_rectangle<Point>> &mp : m ) {
if( mp.second.contains( p ) ) {
func( mp );
cnt++;
if( first_only ) {
break;
}
}
}
return cnt;
}

template<typename Index, typename Point>
int run_for_point_in( const std::map<Index, inclusive_rectangle<Point>> &m, const Point &p,
const std::function<void( const std::pair<Index, inclusive_rectangle<Point>> & )> &func,
bool first_only = true )
{
int cnt = 0;
for( const std::pair<const Index, inclusive_rectangle<Point>> &mp : m ) {
if( mp.second.contains( p ) ) {
func( mp );
cnt++;
if( first_only ) {
break;
}
}
}
return cnt;
}

static constexpr rectangle<point> rectangle_zero( point_zero, point_zero );
static constexpr cuboid<tripoint> cuboid_zero( tripoint_zero, tripoint_zero );

Expand Down
47 changes: 41 additions & 6 deletions src/help.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,11 @@ std::string help::get_dir_grid()
return movement;
}

void help::draw_menu( const catacurses::window &win ) const
std::map<int, inclusive_rectangle<point>> help::draw_menu( const catacurses::window &win,
int selected ) const
{
std::map<int, inclusive_rectangle<point>> opt_map;

werase( win );
// NOLINTNEXTLINE(cata-use-named-point-constants)
int y = fold_and_print( win, point( 1, 0 ), getmaxx( win ) - 2, c_white,
Expand All @@ -105,16 +108,23 @@ void help::draw_menu( const catacurses::window &win ) const
size_t i = 0;
for( const auto &text : help_texts ) {
const std::string cat_name = text.second.first.translated();
const int cat_width = utf8_width( remove_color_tags( shortcut_text( c_white, cat_name ) ) );
if( i < half_size ) {
second_column = std::max( second_column, utf8_width( cat_name ) + 4 );
second_column = std::max( second_column, cat_width + 4 );
}

shortcut_print( win, point( i < half_size ? 1 : second_column, y + i % half_size ),
c_white, c_light_blue, cat_name );
const point sc_start( i < half_size ? 1 : second_column, y + i % half_size );
shortcut_print( win, sc_start, selected == text.first ? hilite( c_white ) : c_white,
selected == text.first ? hilite( c_light_blue ) : c_light_blue, cat_name );
++i;

opt_map.emplace( text.first,
inclusive_rectangle<point>( sc_start, sc_start + point( cat_width - 1, 0 ) ) );
}

wnoutrefresh( win );

return opt_map;
}

std::string help::get_note_colors()
Expand Down Expand Up @@ -149,19 +159,24 @@ void help::display_help() const
init_windows( ui );
ui.on_screen_resize( init_windows );

input_context ctxt( "default", keyboard_mode::keychar );
input_context ctxt( "DISPLAY_HELP", keyboard_mode::keychar );
ctxt.register_cardinal();
ctxt.register_action( "QUIT" );
ctxt.register_action( "CONFIRM" );
// for mouse selection
ctxt.register_action( "SELECT" );
ctxt.register_action( "MOUSE_MOVE" );
// for the menu shortcuts
ctxt.register_action( "ANY_INPUT" );

std::string action;
std::map<int, inclusive_rectangle<point>> opt_map;
int sel = -1;

ui.on_redraw( [&]( const ui_adaptor & ) {
draw_border( w_help_border, BORDER_COLOR, _( "Help" ) );
wnoutrefresh( w_help_border );
draw_menu( w_help );
opt_map = draw_menu( w_help, sel );
} );

std::map<int, std::vector<std::string>> hotkeys;
Expand All @@ -172,8 +187,28 @@ void help::display_help() const
do {
ui_manager::redraw();

sel = -1;
action = ctxt.handle_input();
std::string sInput = ctxt.get_raw_input().text;

// Mouse selection
if( action == "MOUSE_MOVE" || action == "SELECT" ) {
cata::optional<point> coord = ctxt.get_coordinates_text( w_help );
if( !!coord ) {
int cnt = run_for_point_in<int, point>( opt_map, *coord,
[&sel]( const std::pair<int, inclusive_rectangle<point>> &p ) {
sel = p.first;
} );
if( cnt > 0 && action == "SELECT" ) {
auto iter = hotkeys.find( sel );
if( iter != hotkeys.end() && !iter->second.empty() ) {
sInput = iter->second.front();
action = "CONFIRM";
}
}
}
}

for( const auto &hotkey_entry : hotkeys ) {
auto help_text_it = help_texts.find( hotkey_entry.first );
if( help_text_it == help_texts.end() ) {
Expand Down
5 changes: 4 additions & 1 deletion src/help.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <utility>
#include <vector>

#include "cuboid_rectangle.h"

class JsonIn;
class translation;
namespace catacurses
Expand All @@ -23,7 +25,8 @@ class help

private:
void deserialize( JsonIn &jsin );
void draw_menu( const catacurses::window &win ) const;
std::map<int, inclusive_rectangle<point>> draw_menu( const catacurses::window &win,
int selected ) const;
static std::string get_note_colors();
static std::string get_dir_grid();

Expand Down
19 changes: 7 additions & 12 deletions src/main_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,7 @@ void main_menu::on_move() const

void main_menu::on_error()
{
if( errflag ) {
return;
}
sfx::play_variant_sound( "menu_error", "default", 100 );
errflag = true;
}

void main_menu::clear_error()
{
errflag = false;
}

//CJK characters have a width of 2, etc
Expand Down Expand Up @@ -683,6 +674,7 @@ bool main_menu::opening_screen()
sel1 = it.second;
sel2 = sel1 == getopt( main_menu_opts::LOADCHAR ) ? last_world_pos : 0;
sel_line = 0;
on_move();
}
if( action == "SELECT" &&
( sel1 == getopt( main_menu_opts::HELP ) || sel1 == getopt( main_menu_opts::QUIT ) ) ) {
Expand All @@ -694,6 +686,9 @@ bool main_menu::opening_screen()
}
for( const auto &it : main_menu_sub_button_map ) {
if( coord.has_value() && it.first.contains( coord.value() ) ) {
if( sel1 != it.second.first || sel2 != it.second.second ) {
on_move();
}
sel1 = it.second.first;
sel2 = it.second.second;
sel_line = 0;
Expand Down Expand Up @@ -796,7 +791,6 @@ bool main_menu::opening_screen()
if( MAP_SHARING::isSharing() ) {
on_error();
popup( _( "Special games don't work with shared maps." ) );
clear_error();
} else if( sel2 >= 0 && sel2 < static_cast<int>( special_game_type::NUM_SPECIAL_GAME_TYPES ) - 1 ) {
on_out_of_scope cleanup( [&player_character]() {
g->gamemode.reset();
Expand Down Expand Up @@ -866,7 +860,6 @@ bool main_menu::new_character_tab()
if( templates.empty() ) {
on_error();
popup( _( "No templates found!" ) );
clear_error();
return false;
}
while( true ) {
Expand All @@ -876,6 +869,7 @@ bool main_menu::new_character_tab()
for( const std::string &tmpl : templates ) {
mmenu.entries.emplace_back( opt_val++, true, MENU_AUTOASSIGN, tmpl );
}
mmenu.entries.emplace_back( opt_val, true, 'q', _( "<- Back to main menu" ), c_yellow, c_yellow );
mmenu.query();
opt_val = mmenu.ret;
if( opt_val < 0 || static_cast<size_t>( opt_val ) >= templates.size() ) {
Expand Down Expand Up @@ -994,7 +988,6 @@ bool main_menu::load_character_tab( const std::string &worldname )
on_error();
//~ %s = world name
popup( _( "%s has no characters to load!" ), worldname );
clear_error();
return false;
}

Expand All @@ -1004,6 +997,7 @@ bool main_menu::load_character_tab( const std::string &worldname )
for( const save_t &s : savegames ) {
mmenu.entries.emplace_back( opt_val++, true, MENU_AUTOASSIGN, s.decoded_name() );
}
mmenu.entries.emplace_back( opt_val, true, 'q', _( "<- Back to main menu" ), c_yellow, c_yellow );
mmenu.query();
opt_val = mmenu.ret;
if( opt_val < 0 || static_cast<size_t>( opt_val ) >= savegames.size() ) {
Expand Down Expand Up @@ -1053,6 +1047,7 @@ void main_menu::world_tab( const std::string &worldname )
mmenu.entries.emplace_back( opt_val++, true, MENU_AUTOASSIGN,
remove_color_tags( shortcut_text( c_white, it ) ) );
}
mmenu.entries.emplace_back( opt_val, true, 'q', _( "<- Back to main menu" ), c_yellow, c_yellow );
mmenu.query();
opt_val = mmenu.ret;
if( opt_val < 0 || static_cast<size_t>( opt_val ) >= vWorldSubItems.size() ) {
Expand Down
7 changes: 1 addition & 6 deletions src/main_menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,8 @@ class main_menu
// Play a sound whenever the user moves left or right in the main menu or its tabs
void on_move() const;

// Flag to be set when first entering an error condition, cleared when leaving it
// Used to prevent error sound from playing repeatedly at input polling rate
bool errflag = false;
// Play a sound *once* when an error occurs in the main menu or its tabs; sets errflag
// Play a sound *once* when an error occurs in the main menu or its tabs
void on_error();
// Clears errflag
void clear_error();

// Tab functions. They return whether a game was started or not. The ones that can never
// start a game have a void return type.
Expand Down
Loading

0 comments on commit 1e56d2a

Please sign in to comment.