wesnoth/src/gui/dialogs/statistics_dialog.cpp
2017-09-01 23:24:04 +03:00

275 lines
7.4 KiB
C++

/*
Copyright (C) 2016 - 2017 by the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "gui/dialogs/statistics_dialog.hpp"
#include "font/constants.hpp"
#include "formatter.hpp"
#include "gettext.hpp"
#include "gui/auxiliary/find_widget.hpp"
#include "gui/dialogs/helper.hpp"
#include "gui/widgets/label.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/menu_button.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/window.hpp"
#include "team.hpp"
#include "units/types.hpp"
#include "utils/functional.hpp"
#include <iostream>
namespace gui2
{
namespace dialogs
{
static bool use_campaign = false;
REGISTER_DIALOG(statistics_dialog)
statistics_dialog::statistics_dialog(const team& current_team)
: current_team_(current_team)
, campaign_(statistics::calculate_stats(current_team.save_id()))
, scenarios_(statistics::level_stats(current_team.save_id()))
, scenario_index_(scenarios_.size() - 1)
, main_stat_table_()
{
set_restore(true);
}
void statistics_dialog::pre_show(window& window)
{
//
// Set title
//
label& title = find_widget<label>(&window, "title", false);
title.set_label((formatter() << title.get_label() << " (" << current_team_.side_name() << ")").str());
//
// Set up scenario menu
//
std::vector<config> menu_items;
for(const auto& scenario : scenarios_) {
menu_items.emplace_back(config {"label", *scenario.first});
}
menu_button& scenario_menu = find_widget<menu_button>(&window, "scenario_menu", false);
scenario_menu.set_values(menu_items, scenario_index_);
scenario_menu.connect_click_handler(std::bind(&statistics_dialog::on_scenario_select, this, std::ref(window)));
//
// Set up tab toggle
//
listbox& tab_bar = find_widget<listbox>(&window, "tab_bar", false);
tab_bar.select_row(use_campaign);
connect_signal_notify_modified(tab_bar,
std::bind(&statistics_dialog::on_tab_select, this, std::ref(window)));
//
// Set up primary stats list
//
listbox& stat_list = find_widget<listbox>(&window, "stats_list_main", false);
connect_signal_notify_modified(stat_list,
std::bind(&statistics_dialog::on_primary_list_select, this, std::ref(window)));
update_lists(window);
}
inline const statistics::stats& statistics_dialog::current_stats()
{
return use_campaign ? campaign_ : *scenarios_[scenario_index_].second;
}
void statistics_dialog::add_stat_row(window& window, const std::string& type, const statistics::stats::str_int_map& value, const bool has_cost)
{
listbox& stat_list = find_widget<listbox>(&window, "stats_list_main", false);
std::map<std::string, string_map> data;
string_map item;
item["label"] = type;
data.emplace("stat_type", item);
item["label"] = std::to_string(statistics::sum_str_int_map(value));
data.emplace("stat_detail", item);
item["label"] = has_cost ? std::to_string(statistics::sum_cost_str_int_map(value)) : font::unicode_em_dash;
data.emplace("stat_cost", item);
stat_list.add_row(data);
main_stat_table_.push_back(&value);
}
void statistics_dialog::add_damage_row(
window& window,
const std::string& type,
const long long& damage,
const long long& expected,
const long long& turn_damage,
const long long& turn_expected,
const bool show_this_turn)
{
listbox& damage_list = find_widget<listbox>(&window, "stats_list_damage", false);
std::map<std::string, string_map> data;
string_map item;
item["label"] = type;
data.emplace("damage_type", item);
const int shift = statistics::stats::decimal_shift;
const long long dsa = shift * damage - expected;
const long long dst = shift * turn_damage - turn_expected;
std::ostringstream str;
str << damage << " / "
<< (expected * 10 + shift / 2) / shift * 0.1
<< " " // TODO: should probably make this two columns
<< ((dsa < 0) ^ (expected < 0) ? "" : "+")
<< (expected == 0 ? 0 : 100 * dsa / expected) << '%';
item["label"] = str.str();
data.emplace("damage_overall", item);
str.str("");
if(show_this_turn) {
str << turn_damage << " / "
<< (turn_expected * 10 + shift / 2) / shift / 10
<< " " // TODO: should probably make this two columns
<< ((dst < 0) ^ (turn_expected < 0) ? "" : "+")
<< (turn_expected == 0 ? 0 : 100 * dst / turn_expected) << '%';
item["label"] = str.str();
data.emplace("damage_this_turn", item);
}
damage_list.add_row(data);
}
void statistics_dialog::update_lists(window& window)
{
//
// Update primary stats list
//
listbox& stat_list = find_widget<listbox>(&window, "stats_list_main", false);
stat_list.clear();
main_stat_table_.clear();
const statistics::stats& stats = current_stats();
add_stat_row(window, _("Recruits"), stats.recruits);
add_stat_row(window, _("Recalls"), stats.recalls);
add_stat_row(window, _("Advancements"), stats.advanced_to, false);
add_stat_row(window, _("Losses"), stats.deaths);
add_stat_row(window, _("Kills"), stats.killed);
// Update unit count list
on_primary_list_select(window);
//
// Update damage stats list
//
const bool show_this_turn = use_campaign || scenario_index_ + 1 == scenarios_.size();
listbox& damage_list = find_widget<listbox>(&window, "stats_list_damage", false);
damage_list.clear();
add_damage_row(window, _("Inflicted"),
stats.damage_inflicted,
stats.expected_damage_inflicted,
stats.turn_damage_inflicted,
stats.turn_expected_damage_inflicted,
show_this_turn
);
add_damage_row(window, _("Taken"),
stats.damage_taken,
stats.expected_damage_taken,
stats.turn_damage_taken,
stats.turn_expected_damage_taken,
show_this_turn
);
}
void statistics_dialog::on_tab_select(window& window)
{
const bool is_campaign_tab = find_widget<listbox>(&window, "tab_bar", false).get_selected_row() == 1;
if(use_campaign != is_campaign_tab) {
use_campaign = is_campaign_tab;
update_lists(window);
}
}
void statistics_dialog::on_scenario_select(window& window)
{
const size_t new_index = find_widget<menu_button>(&window, "scenario_menu", false).get_value();
if(scenario_index_ != new_index) {
scenario_index_ = new_index;
update_lists(window);
}
}
void statistics_dialog::on_primary_list_select(window& window)
{
const int selected_row = find_widget<listbox>(&window, "stats_list_main", false).get_selected_row();
if(selected_row == -1) {
return;
}
listbox& unit_list = find_widget<listbox>(&window, "stats_list_units", false);
unit_list.clear();
for(const auto& i : *main_stat_table_[selected_row]) {
const unit_type* type = unit_types.find(i.first);
if(!type) {
continue;
}
std::map<std::string, string_map> data;
string_map item;
item["label"] = (formatter() << type->image() << "~RC(" << type->flag_rgb() << ">" << current_team_.color() << ")").str();
data.emplace("unit_image", item);
item["label"] = type->type_name();
data.emplace("unit_name", item);
item["label"] = (formatter() << i.second << font::unicode_multiplication_sign).str();
data.emplace("unit_count", item);
unit_list.add_row(data);
}
}
} // namespace dialogs
} // namespace gui2