diff --git a/src/output.cpp b/src/output.cpp index 5b420ca550299..0e1434be74e62 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -1822,6 +1822,71 @@ std::string get_labeled_bar( const double val, const int width, const std::strin return get_labeled_bar( val, width, label, ratings.begin(), ratings.end() ); } +/** + * Inserts a table into a window, with data right-aligned. + * @param pad Reduce table width by padding left side. + * @param line Line to insert table. + * @param columns Number of columns. Can be 1. + * @param nc_color &FG Default color of table text. + * @param divider To insert a character separating table entries. Can be blank. + * @param r_align true for right aligned, false for left aligned. + * @param data Text data to fill. + * Make sure each entry of the data vector fits into one cell, including divider if any. + */ +void insert_table( const catacurses::window &w, int pad, int line, int columns, + const nc_color &FG, const std::string ÷r, bool r_align, + const std::vector<std::string> &data ) +{ + const int width = getmaxx( w ); + const int rows = getmaxy( w ); + const int col_width = ( ( width - pad ) / columns ); + int indent = 1; // 1 for right window border + if( r_align ) { + indent = ( col_width * columns ) + 1; + } + int div = columns - 1; + int offset = 0; + +#if defined(__ANDROID__) + input_context ctxt( "INSERT_TABLE" ); +#endif + wattron( w, FG ); + for( int i = 0; i < rows * columns; i++ ) { + if( i + offset * columns >= static_cast<int>( data.size() ) ) { + break; + } + int y = line + ( i / columns ); + if( r_align ) { + indent -= col_width; + } + if( div != 0 ) { + if( r_align ) { + right_print( w, y, indent - utf8_width( divider ), FG, divider ); + } else { + fold_and_print_from( w, point( indent + col_width - utf8_width( divider ), y ), + utf8_width( divider ), 0, FG, divider ); + } + div--; + } else { + div = columns - 1; + } + + if( r_align ) { + right_print( w, y, indent, c_white, data[i + offset * columns] ); + if( indent == 1 ) { + indent = ( col_width * columns ) + 1; + } + } else { + fold_and_print_from( w, point( indent, y ), col_width, 0, c_white, data[i + offset * columns] ); + indent += col_width; + if( indent == ( col_width * columns ) + 1 ) { + indent = 1; + } + } + } + wattroff( w, FG ); +} + scrollingcombattext::cSCT::cSCT( const point &p_pos, const direction p_oDir, const std::string &p_sText, const game_message_type p_gmt, const std::string &p_sText2, const game_message_type p_gmt2, diff --git a/src/output.h b/src/output.h index 49690e134313a..1734b04bfe006 100644 --- a/src/output.h +++ b/src/output.h @@ -323,6 +323,9 @@ void center_print( const catacurses::window &w, int y, const nc_color &FG, const std::string &text ); int right_print( const catacurses::window &w, int line, int right_indent, const nc_color &FG, const std::string &text ); +void insert_table( const catacurses::window &w, int pad, int line, int columns, + const nc_color &FG, const std::string ÷r, bool r_align, + const std::vector<std::string> &data ); void scrollable_text( const catacurses::window &w, const std::string &title, const std::string &text ); void scrollable_text( const std::function<catacurses::window()> &init_window, diff --git a/src/ranged.cpp b/src/ranged.cpp index 61982516d2fb1..b29043e426bbf 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -1246,6 +1246,10 @@ static int print_ranged_chance( const player &p, const catacurses::window &w, in window_width -= bars_pad; } + std::string label_m = _( "Moves" ); + std::vector<std::string> t_aims( 4 ), t_confidence( 16 ); + int aim_iter = 0, conf_iter = 0; + nc_color col = c_dark_gray; std::vector<aim_type> aim_types; @@ -1277,6 +1281,19 @@ static int print_ranged_chance( const player &p, const catacurses::window &w, in } line_number++; } + if( ( panel_type == "compact" || panel_type == "labels-narrow" ) && display_type == "numbers" ) { + std::string symbols = _( " <color_green>Great</color> - <color_light_gray>Normal</color>" + " - <color_magenta>Graze</color> - <color_light_blue>Moves</color>" ); + fold_and_print( w, point( 1, line_number++ ), window_width + bars_pad, + c_dark_gray, symbols ); + int len = utf8_width( symbols ) - 96; // 96 to subtract color codes + if( len > window_width + bars_pad ) { + line_number++; + } + for( int i = 0; i < window_width; i++ ) { + mvwprintw( w, point( i + 1, line_number ), "-" ); + } + } const auto front_or = [&]( const std::string & s, const char fallback ) { const auto keys = ctxt.keys_bound_to( s ); @@ -1305,11 +1322,16 @@ static int print_ranged_chance( const player &p, const catacurses::window &w, in } auto hotkey = front_or( type.action.empty() ? "FIRE" : type.action, ' ' ); - if( ( panel_type == "compact" || panel_type == "labels-narrow" ) && display_type != "numbers" ) { - print_colored_text( w, point( 1, line_number ), col, col, string_format( _( "%s %s:" ), label, - aim_l ) ); - right_print( w, line_number++, 1, c_light_blue, _( "Moves" ) ); - right_print( w, line_number, 1, c_light_blue, string_format( "%d", moves_to_fire ) ); + if( ( panel_type == "compact" || panel_type == "labels-narrow" ) ) { + if( display_type == "numbers" ) { + t_aims[aim_iter] = string_format( "<color_dark_gray>%s:</color>", label ); + t_confidence[( aim_iter * 4 ) + 3] = string_format( "<color_light_blue>%d</color>", moves_to_fire ); + } else { + print_colored_text( w, point( 1, line_number ), col, col, string_format( _( "%s %s:" ), label, + aim_l ) ); + right_print( w, line_number++, 1, c_light_blue, _( "Moves" ) ); + right_print( w, line_number, 1, c_light_blue, string_format( "%d", moves_to_fire ) ); + } } else { print_colored_text( w, point( 1, line_number++ ), col, col, string_format( _( "<color_white>[%s]</color> %s %s: Moves to fire: " @@ -1320,17 +1342,31 @@ static int print_ranged_chance( const player &p, const catacurses::window &w, in double confidence = confidence_estimate( range, target_size, current_dispersion ); if( display_type == "numbers" ) { - int last_chance = 0; - std::string confidence_s = enumerate_as_string( confidence_config.begin(), confidence_config.end(), - [&]( const confidence_rating & config ) { - // TODO: Consider not printing 0 chances, but only if you can print something (at least miss 100% or so) - int chance = std::min<int>( 100, 100.0 * ( config.aim_level * confidence ) ) - last_chance; - last_chance += chance; - return string_format( "%s: <color_%s>%3d%%</color>", pgettext( "aim_confidence", - config.label.c_str() ), config.color, chance ); - }, enumeration_conjunction::none ); - line_number += fold_and_print_from( w, point( 1, line_number ), window_width, 0, - c_dark_gray, confidence_s ); + if( panel_type == "compact" || panel_type == "labels-narrow" ) { + int last_chance = 0; + for( const confidence_rating &cr : confidence_config ) { + int chance = std::min<int>( 100, 100.0 * ( cr.aim_level ) * confidence ) - last_chance; + last_chance += chance; + t_confidence[conf_iter] = string_format( "<color_%s>%3d%%</color>", cr.color, chance ); + conf_iter++; + if( conf_iter == ( aim_iter * 4 ) + 3 ) { + conf_iter++; + } + } + aim_iter++; + } else { + int last_chance = 0; + std::string confidence_s = enumerate_as_string( confidence_config.begin(), confidence_config.end(), + [&]( const confidence_rating & config ) { + // TODO: Consider not printing 0 chances, but only if you can print something (at least miss 100% or so) + int chance = std::min<int>( 100, 100.0 * ( config.aim_level * confidence ) ) - last_chance; + last_chance += chance; + return string_format( "%s: <color_%s>%3d%%</color>", pgettext( "aim_confidence", + config.label.c_str() ), config.color, chance ); + }, enumeration_conjunction::none ); + line_number += fold_and_print_from( w, point( 1, line_number ), window_width, 0, + c_dark_gray, confidence_s ); + } } else { std::vector<std::tuple<double, char, std::string>> confidence_ratings; std::transform( confidence_config.begin(), confidence_config.end(), @@ -1347,6 +1383,15 @@ static int print_ranged_chance( const player &p, const catacurses::window &w, in } } + // Draw tables for compact Numbers display + if( ( panel_type == "compact" || panel_type == "labels-narrow" ) + && display_type == "numbers" ) { + const std::string divider = "|"; + int left_pad = 10, columns = 4; + insert_table( w, left_pad, ++line_number, columns, c_light_gray, divider, true, t_confidence ); + insert_table( w, 0, line_number, 1, c_light_gray, "", false, t_aims ); + line_number = line_number + 4; // 4 to account for the tables + } return line_number; } @@ -2051,10 +2096,9 @@ target_handler::trajectory target_ui::run( player &pc, ExitCode *exit_code ) void target_ui::init_window_and_input( player &pc ) { - // TODO: make 'narrow' layout work for 'numbers' display type std::string display_type = get_option<std::string>( "ACCURACY_DISPLAY" ); std::string panel_type = panel_manager::get_manager().get_current_layout_id(); - narrow = ( panel_type == "compact" || panel_type == "labels-narrow" ) && display_type != "numbers"; + narrow = ( panel_type == "compact" || panel_type == "labels-narrow" ); int top = 0; int width;