Skip to content

Commit fff5944

Browse files
mqrausemqrause
andauthored
genericize iteminfo table drawing (#82558)
Co-authored-by: mqrause <[email protected]>
1 parent d92a2a4 commit fff5944

File tree

4 files changed

+127
-82
lines changed

4 files changed

+127
-82
lines changed

src/item.cpp

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3852,30 +3852,39 @@ void item::armor_protection_info( std::vector<iteminfo> &info, const iteminfo_qu
38523852

38533853
// get the layers this bit of the armor covers if its unique compared to the rest of the armor
38543854
for( const layer_level &ll : get_layer( sbp ) ) {
3855-
layering += string_format( " <stat>%s</stat>.", item::layer_to_string( ll ) );
3855+
layering += string_format( "<stat>%s</stat>. ", item::layer_to_string( ll ) );
38563856
}
3857+
// remove extra space from the end
3858+
if( !layering.empty() ) {
3859+
layering.pop_back();
3860+
}
3861+
3862+
std::string coverage_table;
38573863
//~ Limb-specific coverage (%s = name of limb)
3858-
info.emplace_back( "SPECIAL_ARMOR_GRAPH", string_format( _( "<bold>Coverage</bold>:%s" ),
3859-
layering ) );
3864+
coverage_table += string_format( _( "<bold>Coverage</bold>,%s\n" ), layering );
38603865
//~ Regular/Default coverage
3861-
info.emplace_back( bp_cat, string_format( "%s%s%s", space, _( "Default:" ), space ), "",
3862-
iteminfo::no_flags, get_coverage( sbp ) );
3866+
coverage_table += string_format( "%s,<color_c_yellow>%d</color>\n", _( "Default" ),
3867+
get_coverage( sbp ) );
38633868
if( get_coverage( sbp ) != get_coverage( sbp, item::cover_type::COVER_MELEE ) ) {
38643869
//~ Melee coverage
3865-
info.emplace_back( bp_cat, string_format( "%s%s%s", space, _( "Melee:" ), space ), "",
3866-
iteminfo::no_flags, get_coverage( sbp, item::cover_type::COVER_MELEE ) );
3870+
coverage_table += string_format( "%s,<color_c_yellow>%d</color>\n", _( "Melee" ), get_coverage( sbp,
3871+
item::cover_type::COVER_MELEE ) );
38673872
}
38683873
if( get_coverage( sbp ) != get_coverage( sbp, item::cover_type::COVER_RANGED ) ) {
38693874
//~ Ranged coverage
3870-
info.emplace_back( bp_cat, string_format( "%s%s%s", space, _( "Ranged:" ), space ), "",
3871-
iteminfo::no_flags, get_coverage( sbp, item::cover_type::COVER_RANGED ) );
3875+
coverage_table += string_format( "%s,<color_c_yellow>%d</color>\n", _( "Ranged" ),
3876+
get_coverage( sbp,
3877+
item::cover_type::COVER_RANGED ) );
38723878
}
38733879
if( get_coverage( sbp, item::cover_type::COVER_VITALS ) > 0 ) {
38743880
//~ Vitals coverage
3875-
info.emplace_back( bp_cat, string_format( "%s%s%s", space, _( "Vitals:" ), space ), "",
3876-
iteminfo::no_flags, get_coverage( sbp, item::cover_type::COVER_VITALS ) );
3881+
coverage_table += string_format( "%s,<color_c_yellow>%d</color>\n", _( "Vitals" ),
3882+
get_coverage( sbp,
3883+
item::cover_type::COVER_VITALS ) );
38773884
}
38783885

3886+
info.emplace_back( bp_cat, coverage_table, iteminfo::is_table );
3887+
38793888
bool printed_any = false;
38803889

38813890
// gather all the protection data
@@ -3896,17 +3905,17 @@ void item::armor_protection_info( std::vector<iteminfo> &info, const iteminfo_qu
38963905

38973906
bool display_median = percent_best < 50 && percent_worst < 50;
38983907

3908+
std::string protection_table;
38993909
if( display_median ) {
3900-
info.emplace_back( "SPECIAL_ARMOR_GRAPH",
3901-
string_format( "<bold>%s</bold>: <bad>%d%%</bad> chance, <color_c_yellow>Median</color> chance, <good>%d%%</good> chance",
3902-
_( "Protection" ), percent_worst, percent_best ) );
3910+
protection_table +=
3911+
string_format( "<bold>%s</bold>,<bad>%d%%</bad> chance,<color_c_yellow>Median</color> chance,<good>%d%%</good> chance\n",
3912+
_( "Protection" ), percent_worst, percent_best );
39033913
} else if( percent_worst > 0 ) {
3904-
info.emplace_back( "SPECIAL_ARMOR_GRAPH",
3905-
string_format( "<bold>%s</bold>: <bad>%d%%</bad> chance, <good>%d%%</good> chance",
3906-
_( "Protection" ),
3907-
percent_worst, percent_best ) );
3914+
protection_table +=
3915+
string_format( "<bold>%s</bold>,<bad>%d%%</bad> chance,<good>%d%%</good> chance\n",
3916+
_( "Protection" ), percent_worst, percent_best );
39083917
} else {
3909-
info.emplace_back( "SPECIAL_ARMOR_GRAPH", string_format( "<bold>%s</bold>:", _( "Protection" ) ) );
3918+
protection_table += string_format( "<bold>%s</bold>\n", _( "Protection" ) );
39103919
}
39113920

39123921
for( const damage_info_order &dio : damage_info_order::get_all(
@@ -3918,34 +3927,39 @@ void item::armor_protection_info( std::vector<iteminfo> &info, const iteminfo_qu
39183927
bool skipped_detailed = false;
39193928
if( dio.info_display == damage_info_order::info_disp::DETAILED ) {
39203929
if( display_median ) {
3921-
info.emplace_back( bp_cat,
3922-
string_format( "%s%s: <bad>%.2f</bad>, <color_c_yellow>%.2f</color>, <good>%.2f</good>", space,
3923-
uppercase_first_letter( dio.dmg_type->name.translated() ), worst_res.type_resist( dio.dmg_type ),
3924-
median_res.type_resist( dio.dmg_type ), best_res.type_resist( dio.dmg_type ) ), "",
3925-
iteminfo::no_flags );
3930+
protection_table +=
3931+
string_format( "%s,<bad>%.2f</bad>,<color_c_yellow>%.2f</color>,<good>%.2f</good>\n",
3932+
uppercase_first_letter( dio.dmg_type->name.translated() ), worst_res.type_resist( dio.dmg_type ),
3933+
median_res.type_resist( dio.dmg_type ), best_res.type_resist( dio.dmg_type ) );
39263934
printed_any = true;
39273935
} else if( percent_worst > 0 ) {
3928-
info.emplace_back( bp_cat, string_format( "%s%s: <bad>%.2f</bad>, <good>%.2f</good>", space,
3929-
uppercase_first_letter( dio.dmg_type->name.translated() ),
3930-
worst_res.type_resist( dio.dmg_type ), best_res.type_resist( dio.dmg_type ) ), "",
3931-
iteminfo::no_flags );
3936+
protection_table += string_format( "%s,<bad>%.2f</bad>,<good>%.2f</good>\n",
3937+
uppercase_first_letter( dio.dmg_type->name.translated() ), worst_res.type_resist( dio.dmg_type ),
3938+
best_res.type_resist( dio.dmg_type ) );
39323939
printed_any = true;
39333940
} else {
39343941
skipped_detailed = true;
39353942
}
39363943
}
39373944
if( skipped_detailed || dio.info_display == damage_info_order::info_disp::BASIC ) {
3938-
info.emplace_back( bp_cat, string_format( "%s%s: ", space,
3939-
uppercase_first_letter( dio.dmg_type->name.translated() ) ), "",
3940-
iteminfo::is_decimal, best_res.type_resist( dio.dmg_type ) );
3945+
protection_table += string_format( "%s,<color_c_yellow>%.2f</color>\n",
3946+
uppercase_first_letter( dio.dmg_type->name.translated() ),
3947+
best_res.type_resist( dio.dmg_type ) );
39413948
printed_any = true;
39423949
}
39433950
}
39443951
if( get_base_env_resist( *this ) >= 1 ) {
3945-
info.emplace_back( bp_cat, string_format( "%s%s", space, _( "Environmental: " ) ),
3946-
get_base_env_resist( *this ) );
3952+
protection_table += string_format( "%s,<color_c_yellow>%d</color>\n", _( "Environmental" ),
3953+
get_base_env_resist( *this ) );
39473954
printed_any = true;
39483955
}
3956+
3957+
iteminfo::flags info_flags = iteminfo::is_table;
3958+
if( !printed_any ) {
3959+
info_flags = info_flags | iteminfo::no_newline;
3960+
}
3961+
info.emplace_back( bp_cat, protection_table, info_flags );
3962+
39493963
// if we haven't printed any armor data acknowledge that
39503964
if( !printed_any ) {
39513965
info.emplace_back( bp_cat, string_format( "%s%s", space, _( "Negligible Protection" ) ) );
@@ -13287,6 +13301,7 @@ iteminfo::iteminfo( const std::string &Type, const std::string &Name, const std:
1328713301
bLowerIsBetter = static_cast<bool>( Flags & lower_is_better );
1328813302
bDrawName = !( Flags & no_name );
1328913303
bIsArt = Flags & is_art;
13304+
this->isTable = Flags & is_table;
1329013305
}
1329113306

1329213307
iteminfo::iteminfo( const std::string &Type, const std::string &Name, flags Flags )

src/item.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ struct iteminfo {
146146
/** info is ASCII art (prefer monospaced font) */
147147
bool bIsArt;
148148

149+
/** info is displayed as a table */
150+
bool isTable;
151+
149152
enum flags {
150153
no_flags = 0,
151154
is_decimal = 1 << 0, ///< Print as decimal rather than integer
@@ -155,6 +158,7 @@ struct iteminfo {
155158
no_name = 1 << 4, ///< Do not print the name
156159
show_plus = 1 << 5, ///< Use a + sign for positive values
157160
is_art = 1 << 6, ///< is ascii art (prefer monospaced font)
161+
is_table = 1 << 7, ///< is displayed as table
158162
};
159163

160164
/**

src/output.cpp

Lines changed: 64 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,14 +1153,52 @@ void draw_item_filter_rules( const catacurses::window &win, const int starty, co
11531153
wnoutrefresh( win );
11541154
}
11551155

1156+
static std::string format_table( std::string_view s )
1157+
{
1158+
std::string table;
1159+
1160+
std::vector<std::string> rows = string_split( s, '\n' );
1161+
1162+
if( rows.empty() ) {
1163+
return table;
1164+
}
1165+
1166+
std::vector<std::string> header = string_split( rows[0], ',' );
1167+
table += header[0] + ":";
1168+
for( size_t col = 1; col < header.size(); col++ ) {
1169+
table += ( col == 1 ? " " : ", " ) + header[col];
1170+
}
1171+
if( rows.size() > 1 ) {
1172+
table += '\n';
1173+
}
1174+
1175+
for( size_t row = 1; row < rows.size(); row++ ) {
1176+
if( rows[row].empty() ) {
1177+
continue;
1178+
}
1179+
std::vector<std::string> cols = string_split( rows[row], ',' );
1180+
table += " " + cols[0] + ":";
1181+
for( size_t i = 1; i < cols.size(); i++ ) {
1182+
table += ( i == 1 ? " " : ", " ) + cols[i];
1183+
}
1184+
if( row + 1 < rows.size() && !rows[row + 1].empty() ) {
1185+
table += '\n';
1186+
}
1187+
}
1188+
1189+
return table;
1190+
}
1191+
11561192
std::string format_item_info( const std::vector<iteminfo> &vItemDisplay,
11571193
const std::vector<iteminfo> &vItemCompare )
11581194
{
11591195
std::string buffer;
11601196
bool bIsNewLine = true;
11611197

11621198
for( const iteminfo &i : vItemDisplay ) {
1163-
if( i.sType == "DESCRIPTION" || i.sType == "SPECIAL_ARMOR_GRAPH" ) {
1199+
if( i.isTable ) {
1200+
buffer += format_table( i.sName );
1201+
} else if( i.sType == "DESCRIPTION" ) {
11641202
// Always start a new line for sType == "DESCRIPTION"
11651203
if( !bIsNewLine ) {
11661204
buffer += "\n";
@@ -1268,40 +1306,29 @@ static nc_color get_comparison_color( const iteminfo &i,
12681306
return thisColor;
12691307
}
12701308

1271-
static std::vector<std::string> delimit_armor_text( const iteminfo &i )
1309+
static int get_num_cols( std::vector<std::string> &rows )
12721310
{
1273-
const std::string &raw_text = i.sName;
1274-
// The various lines of text that can be passed in from item::armor_protection_info():
1275-
//
1276-
// Protection:
1277-
// Bash: 2.00, 8.00, 20.00
1278-
// Foo: 6.00, 12.00
1279-
//
1280-
// Yes that first one has no numbers. It puts the value into sValue.
1281-
// So we need multiple passes.
1282-
std::vector<std::string> first_pass = string_split( raw_text, ':' );
1283-
if( first_pass.size() == 2 && i.sValue != "-999" ) {
1284-
// Then the value is in sValue and we need to extract it.
1285-
// So just overwrite the second (empty) string that we just split off.
1286-
first_pass[1] = i.sValue;
1311+
int cols = 0;
1312+
1313+
for( const std::string &row : rows ) {
1314+
cols = std::max( cols, static_cast<int>( string_split( row, ',' ).size() ) );
12871315
}
1288-
const std::string mega_string = string_join( first_pass, ", " );
1289-
const std::vector<std::string> delimited_strings = string_split( mega_string, ',' );
1290-
return delimited_strings;
1316+
1317+
return cols;
12911318
}
12921319

1293-
static void draw_armor_table( const std::vector<iteminfo> &vItemDisplay, const iteminfo &i )
1320+
static void draw_table( std::string_view s )
12941321
{
1295-
if( ImGui::BeginTable( "##ITEMINFO_ARMOR_TABLE", delimit_armor_text( i ).size(),
1296-
ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV ) ) {
1297-
auto info_iter = vItemDisplay.begin() + std::distance( vItemDisplay.data(), &i );
1298-
if( info_iter == vItemDisplay.end() ) {
1299-
// PANIC!
1300-
ImGui::EndTable();
1301-
return;
1302-
}
1322+
std::vector<std::string> rows = string_split( s, '\n' );
1323+
int num_cols = get_num_cols( rows );
13031324

1304-
const std::vector<std::string> chopped_up = delimit_armor_text( *info_iter );
1325+
if( rows.empty() || num_cols == 0 ) {
1326+
return;
1327+
}
1328+
1329+
if( ImGui::BeginTable( "##ITEMINFO_TABLE", num_cols,
1330+
ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV ) ) {
1331+
const std::vector<std::string> chopped_up = string_split( rows.front(), ',' );
13051332
for( const std::string &cell_text : chopped_up ) {
13061333
// this prefix prevents imgui from drawing the text. We still have color tags, which imgui won't parse, so we don't want those exposed to the user.
13071334
// But we still want proper column IDs. So we put them in, but we *hide them* with this.
@@ -1320,19 +1347,18 @@ static void draw_armor_table( const std::vector<iteminfo> &vItemDisplay, const i
13201347
cataimgui::draw_colored_text( chopped_up[i], c_unset );
13211348
}
13221349

1323-
info_iter++;
1324-
1325-
while( info_iter != vItemDisplay.end() && info_iter->sType == "ARMOR" ) {
1350+
for( size_t i = 1; i < rows.size(); i++ ) {
1351+
if( rows[i].empty() ) {
1352+
continue;
1353+
}
13261354
ImGui::TableNextRow();
1327-
const std::vector<std::string> delimited_strings = delimit_armor_text( *info_iter );
1355+
const std::vector<std::string> delimited_strings = string_split( rows[i], ',' );
13281356
for( const std::string &text : delimited_strings ) {
13291357
ImGui::TableNextColumn();
13301358
cataimgui::draw_colored_text( text, c_unset );
13311359
}
1332-
info_iter++;
13331360
}
13341361

1335-
13361362
ImGui::EndTable();
13371363
}
13381364
}
@@ -1345,8 +1371,8 @@ void display_item_info( const std::vector<iteminfo> &vItemDisplay,
13451371
if( i.bIsArt ) {
13461372
cataimgui::PushMonoFont();
13471373
}
1348-
if( i.sType == "SPECIAL_ARMOR_GRAPH" ) {
1349-
draw_armor_table( vItemDisplay, i );
1374+
if( i.isTable ) {
1375+
draw_table( i.sName );
13501376
} else if( i.sType == "DESCRIPTION" ) {
13511377
if( i.bDrawName ) {
13521378
if( i.sName == "--" ) {
@@ -1369,7 +1395,7 @@ void display_item_info( const std::vector<iteminfo> &vItemDisplay,
13691395
bAlreadyHasNewLine = false;
13701396
}
13711397
}
1372-
} else if( i.sType != "ARMOR" ) { // ARMOR is handled by draw_armor_table()
1398+
} else {
13731399
if( i.bDrawName ) {
13741400
cataimgui::TextColoredParagraph( c_light_gray, i.sName );
13751401
bAlreadyHasNewLine = false;

0 commit comments

Comments
 (0)