widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #04093
Re: [Merge] lp:~widelands-dev/widelands/bug-1399621 into lp:widelands
I had overlooked the diff question. The checks only check for the exact object type without inheritance, so I have to teat for all 3 types explicitly.
Diff comments:
> === modified file 'src/wui/building_statistics_menu.cc'
> --- src/wui/building_statistics_menu.cc 2014-11-30 18:49:38 +0000
> +++ src/wui/building_statistics_menu.cc 2015-05-13 06:02:16 +0000
> @@ -19,494 +19,441 @@
>
> #include "wui/building_statistics_menu.h"
>
> -#include <vector>
> -
> #include <boost/bind.hpp>
> #include <boost/format.hpp>
>
> #include "base/i18n.h"
> -#include "base/macros.h"
> -#include "graphic/graphic.h"
> -#include "graphic/rendertarget.h"
> -#include "logic/building.h"
> #include "logic/player.h"
> #include "logic/productionsite.h"
> #include "logic/tribe.h"
> -#include "ui_basic/button.h"
> -#include "wui/interactive_player.h"
> -#include "wui/mapviewpixelconstants.h"
> -#include "wui/plot_area.h"
> -
> -#define WINDOW_WIDTH 625
> -#define WINDOW_HEIGHT 440
> -#define VMARGIN 5
> -#define HMARGIN 5
> -#define VSPACING 5
> -#define HSPACING 5
> -#define BUILDING_LIST_HEIGHT 285
> -#define BUILDING_LIST_WIDTH (WINDOW_WIDTH - HMARGIN - HMARGIN)
> -#define LABEL_X 200
> -#define LABEL_WIDTH 150
> -#define VALUE_X (LABEL_X + LABEL_WIDTH)
> -#define JUMP_PREV_BUTTON_X (WINDOW_WIDTH - HMARGIN - 24 - HSPACING - 24)
> -#define JUMP_NEXT_BUTTON_X (WINDOW_WIDTH - HMARGIN - 24)
> -#define TOTAL_PRODUCTIVITY_Y (VMARGIN + BUILDING_LIST_HEIGHT + VSPACING + 22)
> -#define PROGRESS_BAR_Y (TOTAL_PRODUCTIVITY_Y + 24)
> -#define OWNED_Y (PROGRESS_BAR_Y + 24)
> -#define IN_BUILD_Y (OWNED_Y + 24)
> -#define UNPRODUCTIVE_Y (IN_BUILD_Y + 24)
> -#define FLAG_POINT Point(125, WINDOW_HEIGHT - 8)
> -
> -#define LOW_PROD 33
> -
> -#define UPDATE_TIME 1000 // 1 second, gametime
> -
> -
> -namespace Columns {enum {Name, Size, Prod, Owned, Build};}
> -
> -inline InteractivePlayer & BuildingStatisticsMenu::iplayer() const {
> +
> +constexpr int kTabHeight = 35;
> +constexpr int kBuildGridCellSize = 50;
> +constexpr int kColumns = 5;
> +constexpr int32_t kWindowWidth = kColumns * kBuildGridCellSize;
> +constexpr int32_t kWindowHeight = 485;
> +
> +constexpr uint8_t kLowProduction = 33;
> +constexpr int32_t kUpdateTime = 1000; // 1 second, gametime
> +
> +namespace {
> +// Formats a main text + help text for a tooltip and adds a hint for the shift button.
> +const std::string format_tooltip(const std::string& title, const std::string& helptext) {
> + const std::string color = (boost::format("%02x%02x%02x") % int(UI_FONT_TOOLTIP_CLR.r) %
> + int(UI_FONT_TOOLTIP_CLR.g) % int(UI_FONT_TOOLTIP_CLR.b)).str();
> +
> + const std::string tooltip_format("<rt><p><font face=serif size=%i bold=1 color=%s>%s"
> + "<br><font size=%i>%s<br>%s</font></font></p></rt>");
> +
> + return (boost::format(tooltip_format) % UI_FONT_SIZE_SMALL % color % title % 11 % helptext %
> + _("Hold down SHIFT to step through the buildings from back to front.")).str();
> +}
> +
> +} // namespace
> +
> +inline InteractivePlayer& BuildingStatisticsMenu::iplayer() const {
> return dynamic_cast<InteractivePlayer&>(*get_parent());
> }
>
> -BuildingStatisticsMenu::BuildingStatisticsMenu
> - (InteractivePlayer & parent, UI::UniqueWindow::Registry & registry)
> -:
> - UI::UniqueWindow
> - (&parent, "building_statistics",
> - ®istry,
> - WINDOW_WIDTH, WINDOW_HEIGHT,
> - _("Building Statistics")),
> - m_table
> - (this, HMARGIN, VMARGIN, BUILDING_LIST_WIDTH, BUILDING_LIST_HEIGHT),
> - m_progbar
> - (this,
> - LABEL_X, PROGRESS_BAR_Y, WINDOW_WIDTH - LABEL_X - HMARGIN, 20,
> - UI::ProgressBar::Horizontal),
> - m_total_productivity_label
> - (this,
> - LABEL_X, TOTAL_PRODUCTIVITY_Y, LABEL_WIDTH, 24,
> - _("Total Productivity:"), UI::Align_CenterLeft),
> - m_owned_label
> - (this,
> - LABEL_X, OWNED_Y, LABEL_WIDTH, 24,
> - _("Owned:"), UI::Align_CenterLeft),
> - m_owned
> - (this, VALUE_X, OWNED_Y, 100, 24, UI::Align_CenterLeft),
> - m_in_build_label
> - (this,
> - LABEL_X, IN_BUILD_Y, LABEL_WIDTH, 24,
> - _("Being built:"), UI::Align_CenterLeft),
> - m_in_build
> - (this, VALUE_X, IN_BUILD_Y, 100, 24, UI::Align_CenterLeft),
> - m_unproductive_label
> - (this,
> - LABEL_X, UNPRODUCTIVE_Y, LABEL_WIDTH, 24,
> - _("Jump to unproductive"), UI::Align_CenterLeft),
> - m_anim (0),
> - m_lastupdate (0),
> - m_last_building_index(0),
> - m_last_table_index (0)
> -{
> - // building list
> - m_table.add_column(310, _("Name"));
> - m_table.add_column (70, _("Type"), "", UI::Align_HCenter);
> - m_table.add_column (70, _("Prod"), "", UI::Align_Right);
> - m_table.add_column (70, _("Owned"), "", UI::Align_Right);
> - m_table.add_column (70, _("Build"), "", UI::Align_Right);
> - m_table.selected.connect(boost::bind(&BuildingStatisticsMenu::table_changed, this, _1));
> - m_table.set_column_compare
> - (Columns::Size,
> - boost::bind
> - (&BuildingStatisticsMenu::compare_building_size, this, _1, _2));
> - m_table.focus();
> -
> - // toggle when to run button
> - m_progbar.set_total(100);
> -
> - m_btn[PrevOwned] =
> - new UI::Button
> - (this, "previous_owned",
> - JUMP_PREV_BUTTON_X, OWNED_Y, 24, 24,
> - g_gr->images().get("pics/but4.png"),
> - g_gr->images().get("pics/scrollbar_left.png"),
> - _("Show previous"),
> - false);
> - m_btn[PrevOwned]->sigclicked.connect
> - (boost::bind(&BuildingStatisticsMenu::clicked_jump, boost::ref(*this), PrevOwned));
> -
> - m_btn[NextOwned] =
> - new UI::Button
> - (this, "next_owned",
> - JUMP_NEXT_BUTTON_X, OWNED_Y, 24, 24,
> - g_gr->images().get("pics/but4.png"),
> - g_gr->images().get("pics/scrollbar_right.png"),
> - _("Show next"),
> - false);
> - m_btn[NextOwned]->sigclicked.connect
> - (boost::bind(&BuildingStatisticsMenu::clicked_jump, boost::ref(*this), NextOwned));
> -
> - m_btn[PrevConstruction] =
> - new UI::Button
> - (this, "previous_constructed",
> - JUMP_PREV_BUTTON_X, IN_BUILD_Y, 24, 24,
> - g_gr->images().get("pics/but4.png"),
> - g_gr->images().get("pics/scrollbar_left.png"),
> - _("Show previous"),
> - false);
> - m_btn[PrevConstruction]->sigclicked.connect
> - (boost::bind(&BuildingStatisticsMenu::clicked_jump, boost::ref(*this), PrevConstruction));
> -
> - m_btn[NextConstruction] =
> - new UI::Button
> - (this, "next_constructed",
> - JUMP_NEXT_BUTTON_X, IN_BUILD_Y, 24, 24,
> - g_gr->images().get("pics/but4.png"),
> - g_gr->images().get("pics/scrollbar_right.png"),
> - _("Show next"),
> - false);
> - m_btn[NextConstruction]->sigclicked.connect
> - (boost::bind(&BuildingStatisticsMenu::clicked_jump, boost::ref(*this), NextConstruction));
> -
> - m_btn[PrevUnproductive] =
> - new UI::Button
> - (this, "previous_unproductive",
> - JUMP_PREV_BUTTON_X, UNPRODUCTIVE_Y, 24, 24,
> - g_gr->images().get("pics/but4.png"),
> - g_gr->images().get("pics/scrollbar_left.png"),
> - _("Show previous"),
> - false);
> - m_btn[PrevUnproductive]->sigclicked.connect
> - (boost::bind(&BuildingStatisticsMenu::clicked_jump, boost::ref(*this), PrevUnproductive));
> -
> - m_btn[NextUnproductive] =
> - new UI::Button
> - (this, "next_unproductive",
> - JUMP_NEXT_BUTTON_X, UNPRODUCTIVE_Y, 24, 24,
> - g_gr->images().get("pics/but4.png"),
> - g_gr->images().get("pics/scrollbar_right.png"),
> - _("Show next"),
> - false);
> - m_btn[NextUnproductive]->sigclicked.connect
> - (boost::bind(&BuildingStatisticsMenu::clicked_jump, boost::ref(*this), NextUnproductive));
> -}
> -
> +BuildingStatisticsMenu::BuildingStatisticsMenu(InteractivePlayer& parent,
> + UI::UniqueWindow::Registry& registry)
> + : UI::UniqueWindow(&parent,
> + "building_statistics",
> + ®istry,
> + kWindowWidth,
> + kWindowHeight,
> + _("Building Statistics")),
> + is_shift_pressed_(false),
> + tabs_(this, 0, 0, g_gr->images().get("pics/but1.png")),
> + small_tab_(&tabs_, 0, 0, UI::Box::Vertical),
> + medium_tab_(&tabs_, 0, 0, UI::Box::Vertical),
> + big_tab_(&tabs_, 0, 0, UI::Box::Vertical),
> + mines_tab_(&tabs_, 0, 0, UI::Box::Vertical),
> + ports_tab_(&tabs_, 0, 0, UI::Box::Vertical) {
> + set_pos(Point(0, 40)); // Shift below the Gametime + FPS display
> + tabs_.add("building_stats_small",
> + g_gr->images().get("pics/menu_tab_buildsmall.png"),
> + &small_tab_,
> + _("Small Buildings"));
> + tabs_.add("building_stats_medium",
> + g_gr->images().get("pics/menu_tab_buildmedium.png"),
> + &medium_tab_,
> + _("Medium Buildings"));
> + tabs_.add("building_stats_big",
> + g_gr->images().get("pics/menu_tab_buildbig.png"),
> + &big_tab_,
> + _("Big Buildings"));
> + tabs_.add("building_stats_mines",
> + g_gr->images().get("pics/menu_tab_buildmine.png"),
> + &mines_tab_,
> + _("Mines"));
> + tabs_.add("building_stats_ports",
> + g_gr->images().get("pics/menu_tab_buildport.png"),
> + &ports_tab_,
> + _("Ports"));
> + tabs_.set_size(kWindowWidth, kWindowHeight);
> +
> + const TribeDescr& tribe = iplayer().player().tribe();
> +
> + const BuildingIndex nr_buildings = tribe.get_nrbuildings();
> + building_buttons_ = std::vector<UI::Button*>(nr_buildings);
> + owned_buttons_ = std::vector<UI::Button*>(nr_buildings);
> + productivity_buttons_ = std::vector<UI::Button*>(nr_buildings);
> +
> + // Column counters
> + int small_column = 0;
> + int medium_column = 0;
> + int big_column = 0;
> + int mines_column = 0;
> + int ports_column = 0;
> +
> + UI::Box* mines_row = new UI::Box(&mines_tab_, 0, 0, UI::Box::Horizontal);
> + UI::Box* ports_row = new UI::Box(&ports_tab_, 0, 0, UI::Box::Horizontal);
> + UI::Box* big_row = new UI::Box(&big_tab_, 0, 0, UI::Box::Horizontal);
> + UI::Box* medium_row = new UI::Box(&medium_tab_, 0, 0, UI::Box::Horizontal);
> + UI::Box* small_row = new UI::Box(&small_tab_, 0, 0, UI::Box::Horizontal);
> +
> + for (BuildingIndex id = 0; id < nr_buildings; ++id) {
> + const BuildingDescr& descr = *tribe.get_building_descr(id);
> +
> + if (descr.type() != MapObjectType::CONSTRUCTIONSITE &&
> + descr.type() != MapObjectType::DISMANTLESITE) {
> + if (descr.get_ismine()) {
> + if (add_button(id, descr, mines_tab_, *mines_row, &mines_column)) {
> + mines_row = new UI::Box(&mines_tab_, 0, 0, UI::Box::Horizontal);
> + }
> + } else if (descr.get_isport()) {
> + if (add_button(id, descr, ports_tab_, *ports_row, &ports_column)) {
> + ports_row = new UI::Box(&ports_tab_, 0, 0, UI::Box::Horizontal);
> + }
> + } else {
> + switch (descr.get_size()) {
> + case BaseImmovable::SMALL:
> + if (add_button(id, descr, small_tab_, *small_row, &small_column)) {
> + small_row = new UI::Box(&small_tab_, 0, 0, UI::Box::Horizontal);
> + }
> + break;
> + case BaseImmovable::MEDIUM:
> + if (add_button(id, descr, medium_tab_, *medium_row, &medium_column)) {
> + medium_row = new UI::Box(&medium_tab_, 0, 0, UI::Box::Horizontal);
> + }
> + break;
> + case BaseImmovable::BIG:
> + if (add_button(id, descr, big_tab_, *big_row, &big_column)) {
> + big_row = new UI::Box(&big_tab_, 0, 0, UI::Box::Horizontal);
> + }
> + break;
> + default:
> + throw wexception(
> + "Building statictics: Found building without a size: %s", descr.name().c_str());
> + }
> + }
> + }
> + }
> + mines_tab_.add(mines_row, UI::Align_Left);
> + ports_tab_.add(ports_row, UI::Align_Left);
> + small_tab_.add(small_row, UI::Align_Left);
> + medium_tab_.add(medium_row, UI::Align_Left);
> + big_tab_.add(big_row, UI::Align_Left);
> + update();
> +}
> +
> +// Adds 3 buttons per building type:
> +// - Building image, steps through all buildings of the type
> +// - Buildings owned, steps through constructionsites
> +// - Productivity, steps though buildings with low productivity and stopped buildings
> +bool BuildingStatisticsMenu::add_button(
> + BuildingIndex id, const BuildingDescr& descr, UI::Box& tab, UI::Box& row, int* column) {
> + // Only add headquarter types that are owned by player.
> + if (!(descr.is_buildable() || descr.is_enhanced() || descr.global()) &&
> + iplayer().get_player()->get_building_statistics(id).empty()) {
> + return false;
> + }
> +
> + UI::Box* button_box = new UI::Box(&row, 0, 0, UI::Box::Vertical);
> + building_buttons_[id] = new UI::Button(button_box,
> + (boost::format("building_button%s") % id).str(),
> + 0,
> + 0,
> + kBuildGridCellSize,
> + kBuildGridCellSize,
> + g_gr->images().get("pics/but1.png"),
> + &g_gr->animations()
> + .get_animation(descr.get_animation("idle"))
> + .representative_image_from_disk(),
> + "",
> + false,
> + true);
> + button_box->add(building_buttons_[id], UI::Align_Left);
> +
> + owned_buttons_[id] = new UI::Button(button_box,
> + (boost::format("owned_button%s") % id).str(),
> + 0,
> + 0,
> + kBuildGridCellSize,
> + 20,
> + g_gr->images().get("pics/but1.png"),
> + "",
> + "",
> + false,
> + true);
> + button_box->add(owned_buttons_[id], UI::Align_Left);
> +
> + productivity_buttons_[id] = new UI::Button(button_box,
> + (boost::format("prod_button%s") % id).str(),
> + 0,
> + 0,
> + kBuildGridCellSize,
> + 20,
> + g_gr->images().get("pics/but1.png"),
> + "",
> + "",
> + false,
> + true);
> + button_box->add(productivity_buttons_[id], UI::Align_Left);
> +
> + row.add(button_box, UI::Align_Left);
> +
> + building_buttons_[id]->sigclicked.connect(boost::bind(
> + &BuildingStatisticsMenu::jump_building, boost::ref(*this), id, JumpTarget::kOwned));
> + owned_buttons_[id]->sigclicked.connect(boost::bind(
> + &BuildingStatisticsMenu::jump_building, boost::ref(*this), id, JumpTarget::kConstruction));
> + productivity_buttons_[id]->sigclicked.connect(boost::bind(
> + &BuildingStatisticsMenu::jump_building, boost::ref(*this), id, JumpTarget::kUnproductive));
> +
> + // Check if the row is full
> + ++*column;
> + if (*column == kColumns) {
> + tab.add(&row, UI::Align_Left);
> + *column = 0;
> + return true;
> + }
> + return false;
> +}
> +
> +bool BuildingStatisticsMenu::handle_key(bool const down, SDL_Keysym const code) {
> + if (down) {
> + // only on down events
> + switch (code.sym) {
> + case SDLK_LSHIFT:
> + case SDLK_RSHIFT:
> + is_shift_pressed_ = true;
> + break;
> + default:
> + break;
> + }
> + } else {
> + switch (code.sym) {
> + case SDLK_LSHIFT:
> + case SDLK_RSHIFT:
> + is_shift_pressed_ = false;
> + break;
> + default:
> + break;
> + }
> + }
> + return false;
> +}
> +
> +void BuildingStatisticsMenu::jump_building(BuildingIndex id, JumpTarget target) {
> + if (last_building_type_ != id) {
> + last_building_index_ = 0;
> + }
> + last_building_type_ = id;
> +
> + const std::vector<Player::BuildingStats>& stats_vector =
> + iplayer().get_player()->get_building_statistics(id);
> +
> + switch (target) {
> + case JumpTarget::kOwned: {
> + if (is_shift_pressed_) {
> + --last_building_index_;
> + } else {
> + ++last_building_index_;
> + }
> + break;
> + }
> + case JumpTarget::kConstruction: {
> + int32_t const curindex = last_building_index_;
> +
> + if (is_shift_pressed_) {
> + while (validate_pointer(&(--last_building_index_), stats_vector.size()) != curindex) {
> + if (stats_vector[last_building_index_].is_constructionsite) {
> + break;
> + }
> + }
> + } else {
> + while (validate_pointer(&(++last_building_index_), stats_vector.size()) != curindex) {
> + if (stats_vector[last_building_index_].is_constructionsite) {
> + break;
> + }
> + }
> + }
> + break;
> + }
> + case JumpTarget::kUnproductive: {
> + const Map& map = iplayer().egbase().map();
> +
> + int32_t const curindex = last_building_index_;
> + bool found = false;
> +
> + if (is_shift_pressed_) {
> + while (validate_pointer(&(--last_building_index_), stats_vector.size()) != curindex) {
> + if (!stats_vector[last_building_index_].is_constructionsite) {
> + if (upcast(ProductionSite,
> + productionsite,
> + map[stats_vector[last_building_index_].pos].get_immovable())) {
> + if (productionsite->is_stopped() ||
> + productionsite->get_statistics_percent() < kLowProduction) {
> + found = true;
> + break;
> + }
> + }
> + }
> + }
> + } else {
> + while (validate_pointer(&(++last_building_index_), stats_vector.size()) != curindex) {
> + if (!stats_vector[last_building_index_].is_constructionsite) {
> + if (upcast(ProductionSite,
> + productionsite,
> + map[stats_vector[last_building_index_].pos].get_immovable())) {
> + if (productionsite->is_stopped() ||
> + productionsite->get_statistics_percent() < kLowProduction) {
> + found = true;
> + break;
> + }
> + }
> + }
> + }
> + }
> + if (!found) { // Now look at the old
> + if (upcast(ProductionSite,
> + productionsite,
> + map[stats_vector[last_building_index_].pos].get_immovable())) {
> + if (productionsite->is_stopped() ||
> + productionsite->get_statistics_percent() < kLowProduction) {
> + found = true;
> + }
> + }
> + }
> + break;
> + }
> + default:
> + assert(false);
> + break;
> + }
> +
> + validate_pointer(&last_building_index_, stats_vector.size());
> + iplayer().move_view_to(stats_vector[last_building_index_].pos);
> +}
>
> /*
> * Update this statistic
> */
> void BuildingStatisticsMenu::think() {
> - const Widelands::Game & game = iplayer().game();
> + const Game& game = iplayer().game();
> int32_t const gametime = game.get_gametime();
>
> - if ((gametime - m_lastupdate) > UPDATE_TIME) {
> + if ((gametime - lastupdate_) > kUpdateTime) {
> update();
> - m_lastupdate = gametime;
> + lastupdate_ = gametime;
> }
> }
>
> /*
> - * draw()
> - *
> - * Draw this window
> - */
> -void BuildingStatisticsMenu::draw(RenderTarget & dst) {
> - UI::Window::draw(dst);
> -
> - const Widelands::Player & player = iplayer().player();
> - if (m_anim)
> - dst.drawanim
> - (FLAG_POINT - Point(TRIANGLE_WIDTH / 2, TRIANGLE_HEIGHT),
> - m_anim, 0, &player);
> -}
> -
> -/*
> * validate if this pointer is ok
> */
> -int32_t BuildingStatisticsMenu::validate_pointer
> - (int32_t * const id, int32_t const size)
> -{
> - if (*id < 0)
> +int32_t BuildingStatisticsMenu::validate_pointer(int32_t* const id, int32_t const size) {
> + if (*id < 0) {
> *id = size - 1;
> - if (size <= *id)
> + }
> + if (size <= *id) {
> *id = 0;
> + }
>
> return *id;
> }
>
> -
> -void BuildingStatisticsMenu::clicked_jump(JumpTargets const id) {
> - assert(m_table.has_selection());
> - if (m_last_table_index != m_table.selection_index())
> - m_last_building_index = 0;
> - m_last_table_index = m_table.selection_index();
> - const std::vector<Widelands::Player::BuildingStats> & vec =
> - iplayer().get_player()->get_building_statistics
> - (Widelands::BuildingIndex
> - (static_cast<size_t>(m_table.get_selected())));
> - const Widelands::Map & map = iplayer().egbase().map();
> -
> - bool found = true; // we think, we always find a proper building
> -
> - switch (id) {
> - case PrevOwned:
> - --m_last_building_index;
> - break;
> - case NextOwned:
> - ++m_last_building_index;
> - break;
> - case PrevConstruction: {
> - int32_t const curindex = m_last_building_index;
> - while
> - (validate_pointer(&(--m_last_building_index), vec.size()) != curindex)
> - if (vec[m_last_building_index].is_constructionsite)
> - break;
> - break;
> - }
> - case NextConstruction: {
> - int32_t const curindex = m_last_building_index;
> - while
> - (validate_pointer(&(++m_last_building_index), vec.size()) != curindex)
> - if (vec[m_last_building_index].is_constructionsite)
> - break;
> - break;
> - }
> - case PrevUnproductive: {
> - int32_t const curindex = m_last_building_index;
> - found = false;
> - while (validate_pointer(&(--m_last_building_index), vec.size()) != curindex)
> - if (!vec[m_last_building_index].is_constructionsite) {
> - if
> - (upcast
> - (Widelands::ProductionSite,
> - productionsite,
> - map[vec[m_last_building_index].pos].get_immovable()))
> - if (productionsite->get_statistics_percent() < LOW_PROD) {
> - found = true;
> - break;
> - }
> - }
> - if (!found) // Now look at the old
> - if
> - (upcast
> - (Widelands::ProductionSite,
> - productionsite,
> - map[vec[m_last_building_index].pos].get_immovable()))
> - if (productionsite->get_statistics_percent() < LOW_PROD)
> - found = true;
> - break;
> - }
> - case NextUnproductive: {
> - int32_t const curindex = m_last_building_index;
> - found = false;
> - while
> - (validate_pointer(&(++m_last_building_index), vec.size()) != curindex)
> - if (!vec[m_last_building_index].is_constructionsite) {
> - if
> - (upcast
> - (Widelands::ProductionSite,
> - productionsite,
> - map[vec[m_last_building_index].pos].get_immovable()))
> - if (productionsite->get_statistics_percent() < LOW_PROD) {
> - found = true;
> - break;
> - }
> - }
> - if (!found) // Now look at the old
> - if
> - (upcast
> - (Widelands::ProductionSite,
> - productionsite,
> - map[vec[m_last_building_index].pos].get_immovable()))
> - if (productionsite->get_statistics_percent() < LOW_PROD)
> - found = true;
> - break;
> - }
> - default:
> - assert(false);
> - break;
> - }
> -
> - validate_pointer(&m_last_building_index, vec.size());
> -
> - if (found)
> - iplayer().move_view_to(vec[m_last_building_index].pos);
> -}
> -
> -/*
> - * The table has been selected
> - */
> -void BuildingStatisticsMenu::table_changed(uint32_t) {update();}
> -
> -/**
> - * Callback to sort table based on building size.
> - */
> -bool BuildingStatisticsMenu::compare_building_size
> - (uint32_t const rowa, uint32_t const rowb)
> -{
> - const Widelands::TribeDescr & tribe = iplayer().player().tribe();
> - Widelands::BuildingIndex a = Widelands::BuildingIndex(m_table[rowa]);
> - Widelands::BuildingIndex b = Widelands::BuildingIndex(m_table[rowb]);
> - const Widelands::BuildingDescr * descra = tribe.get_building_descr(a);
> - const Widelands::BuildingDescr * descrb = tribe.get_building_descr(b);
> -
> - if (!descra || !descrb)
> - return false; // shouldn't happen, but be defensive
> -
> - // mines come last
> - if (descrb->get_ismine())
> - return !descra->get_ismine();
> - else if (descra->get_ismine())
> - return false;
> -
> - // smallest first
> - return descra->get_size() < descrb->get_size();
> -}
> -
> -
> -/*
> - * Update table
> +/*
> + * Update Buttons
> */
> void BuildingStatisticsMenu::update() {
> - m_owned .set_text("");
> - m_in_build.set_text("");
> - m_progbar .set_state(0);
> + const Player& player = iplayer().player();
> + const TribeDescr& tribe = player.tribe();
> + const Map& map = iplayer().game().map();
> + const BuildingIndex nr_buildings = tribe.get_nrbuildings();
> + std::string button_tooltip;
>
> - const Widelands::Player & player = iplayer().player();
> - const Widelands::TribeDescr & tribe = player.tribe();
> - const Widelands::Map & map = iplayer().game().map();
> - Widelands::BuildingIndex const nr_buildings = tribe.get_nrbuildings();
> - for
> - (Widelands::BuildingIndex i = 0;
> - i < nr_buildings;
> - ++i)
> - {
> - const Widelands::BuildingDescr & building =
> - *tribe.get_building_descr(i);
> - if
> - (!(building.is_buildable()
> - || building.is_enhanced()
> - || building.global()))
> + for (BuildingIndex id = 0; id < nr_buildings; ++id) {
> + const BuildingDescr& building = *tribe.get_building_descr(id);
> + if (building_buttons_[id] == nullptr) {
> continue;
> -
> - const std::vector<Widelands::Player::BuildingStats> & vec =
> - player.get_building_statistics(i);
> -
> - // walk all entries, add new ones if needed
> - UI::Table<uintptr_t const>::EntryRecord * te = nullptr;
> - const uint32_t table_size = m_table.size();
> - for (uint32_t l = 0; l < table_size; ++l) {
> - UI::Table<uintptr_t const>::EntryRecord & er = m_table.get_record(l);
> - if (UI::Table<uintptr_t const>::get(er) == i) {
> - te = &er;
> - break;
> - }
> - }
> -
> - // If not in list, add new one, as long as this building is enabled.
> - if (!te) {
> - if (! iplayer().player().is_building_type_allowed(i))
> - continue;
> - te = &m_table.add(i);
> - }
> -
> - uint32_t nr_owned = 0;
> - uint32_t nr_build = 0;
> + }
> + assert(productivity_buttons_[id] != nullptr);
> + assert(owned_buttons_[id] != nullptr);
> +
> + const std::vector<Player::BuildingStats>& stats_vector = player.get_building_statistics(id);
> +
> + uint32_t nr_owned = 0;
> + uint32_t nr_build = 0;
> uint32_t total_prod = 0;
> - upcast(Widelands::ProductionSiteDescr const, productionsite, &building);
> - for (uint32_t l = 0; l < vec.size(); ++l) {
> - if (vec[l].is_constructionsite)
> + upcast(ProductionSiteDescr const, productionsite, &building);
> + for (uint32_t l = 0; l < stats_vector.size(); ++l) {
> + if (stats_vector[l].is_constructionsite)
> ++nr_build;
> else {
> ++nr_owned;
> if (productionsite)
> - total_prod +=
> - dynamic_cast<Widelands::ProductionSite&>
> - (*map[vec[l].pos].get_immovable())
> - .get_statistics_percent();
> - }
> - }
> -
> - const bool is_selected = // Is this entry selected?
> - m_table.has_selection() && m_table.get_selected() == i;
> -
> - if (is_selected) {
> - m_anim = building.get_ui_anim();
> - m_btn[PrevOwned] ->set_enabled(nr_owned);
> - m_btn[NextOwned] ->set_enabled(nr_owned);
> - m_btn[PrevConstruction]->set_enabled(nr_build);
> - m_btn[NextConstruction]->set_enabled(nr_build);
> - }
> -
> - // add new Table Entry
> - te->set_picture
> - (Columns::Name, building.get_icon(), building.descname());
> -
> - {
> - char const * pic = "pics/novalue.png";
> - if (building.get_ismine()) {
> - pic = "pics/menu_tab_buildmine.png";
> - } else if (building.get_isport()) {
> - pic = "pics/menu_tab_buildport.png";
> - }
> - else switch (building.get_size()) {
> - case Widelands::BaseImmovable::SMALL:
> - pic = "pics/menu_tab_buildsmall.png";
> - break;
> - case Widelands::BaseImmovable::MEDIUM:
> - pic = "pics/menu_tab_buildmedium.png";
> - break;
> - case Widelands::BaseImmovable::BIG:
> - pic = "pics/menu_tab_buildbig.png";
> - break;
> - default:
> - assert(false);
> - break;
> - }
> - te->set_picture(Columns::Size, g_gr->images().get(pic));
> - }
> -
> - if (productionsite && nr_owned) {
> - uint32_t const percent =
> - static_cast<uint32_t>
> - (static_cast<float>(total_prod) / static_cast<float>(nr_owned));
> - te->set_string(Columns::Prod, (boost::format("%3u") % percent).str()); // space-pad for sort
> - if (is_selected) {
> - m_progbar.set_state(percent);
> - m_btn[PrevUnproductive]->set_enabled(true);
> - m_btn[NextUnproductive]->set_enabled(true);
> - }
> - } else {
> - te->set_string(Columns::Prod, " ");
> - if (is_selected) {
> - m_btn[PrevUnproductive]->set_enabled(false);
> - m_btn[NextUnproductive]->set_enabled(false);
> - }
> - }
> -
> - // number of these buildings
> - const std::string owned_string =
> - (boost::format("%3u") % nr_owned).str(); // space-pad for sort
> - te->set_string(Columns::Owned, owned_string);
> - if (is_selected) {
> - m_owned.set_text(owned_string);
> - }
> -
> - // number of these buildings currently being built
> - const std::string build_string =
> - (boost::format("%3u") % nr_build).str(); // space-pad for sort
> - te->set_string(Columns::Build, build_string);
> - if (is_selected) {
> - m_in_build.set_text(build_string);
> - }
> - }
> -
> - // disable all buttons, if nothing to select
> - if (!m_table.has_selection()) {
> - m_btn[PrevOwned] ->set_enabled(false);
> - m_btn[NextOwned] ->set_enabled(false);
> - m_btn[PrevConstruction]->set_enabled(false);
> - m_btn[NextConstruction]->set_enabled(false);
> - m_btn[PrevUnproductive]->set_enabled(false);
> - m_btn[NextUnproductive]->set_enabled(false);
> + total_prod += dynamic_cast<ProductionSite&>(
> + *map[stats_vector[l].pos].get_immovable()).get_statistics_percent();
> + }
> + }
> +
> + if (building.type() == MapObjectType::PRODUCTIONSITE &&
> + building.type() != MapObjectType::MILITARYSITE &&
> + building.type() != MapObjectType::WAREHOUSE) {
Because unlike is_a or upcast, it gives me the exact building type without inheritance.
> + if (nr_owned) {
> + int const percent =
> + static_cast<int>(static_cast<float>(total_prod) / static_cast<float>(nr_owned));
> + productivity_buttons_[id]->set_title((boost::format("%i%%") % percent).str());
> + productivity_buttons_[id]->set_enabled(true);
> + } else {
> + productivity_buttons_[id]->set_title("–");
> + productivity_buttons_[id]->set_enabled(false);
> + }
> + button_tooltip = _("Productivity");
> + if (productivity_buttons_[id]->enabled()) {
> + button_tooltip = format_tooltip(
> + button_tooltip,
> + _("Click to step through buildings with low productivity and stopped buildings."));
> + }
> + productivity_buttons_[id]->set_tooltip(button_tooltip);
> + } else {
> + productivity_buttons_[id]->set_title(" ");
> + productivity_buttons_[id]->set_enabled(false);
> + }
> +
> + if (!building.global() && (building.is_buildable() || building.is_enhanced())) {
> + /** TRANSLATORS Buildings: owned / under construction */
> + owned_buttons_[id]->set_title((boost::format(_("%1% / %2%")) % nr_owned % nr_build).str());
> + } else {
> + owned_buttons_[id]->set_title((boost::format(_("%1% / %2%")) % nr_owned % "–").str());
> + }
> + owned_buttons_[id]->set_enabled((nr_owned + nr_build) > 0);
> + building_buttons_[id]->set_enabled((nr_owned + nr_build) > 0);
> +
> + button_tooltip = building.descname();
> + if (building_buttons_[id]->enabled()) {
> + button_tooltip =
> + format_tooltip(button_tooltip, _("Click to step through all buildings of this type."));
> + }
> + building_buttons_[id]->set_tooltip(button_tooltip);
> +
> + button_tooltip = _("Owned / Under Construction");
> + if (owned_buttons_[id]->enabled()) {
> + button_tooltip = format_tooltip(
> + button_tooltip, _("Click to step through buildings under construction."));
> + }
> + owned_buttons_[id]->set_tooltip(button_tooltip);
> }
> }
>
> === modified file 'src/wui/building_statistics_menu.h'
> --- src/wui/building_statistics_menu.h 2014-09-10 14:48:40 +0000
> +++ src/wui/building_statistics_menu.h 2015-05-13 06:02:16 +0000
> @@ -20,56 +20,67 @@
> #ifndef WL_WUI_BUILDING_STATISTICS_MENU_H
> #define WL_WUI_BUILDING_STATISTICS_MENU_H
>
> -#include "ui_basic/progressbar.h"
> -#include "ui_basic/table.h"
> -#include "ui_basic/textarea.h"
> +#include <vector>
> +
> +#include "logic/building.h"
> +#include "logic/widelands.h"
> +#include "ui_basic/box.h"
> +#include "ui_basic/button.h"
> +#include "ui_basic/tabpanel.h"
> #include "ui_basic/unique_window.h"
> -
> -namespace Widelands {struct BuildingDescr;}
> -class InteractivePlayer;
> -namespace UI {
> -struct Button;
> -struct ProgressBar;
> -struct Textarea;
> -}
> -
> +#include "wui/interactive_player.h"
> +
> +using namespace Widelands;
> +
> +/// This window shows statistics for all the buildings that the player owns.
> +/// It also allows to jump through buildings on the map.
> struct BuildingStatisticsMenu : public UI::UniqueWindow {
> - BuildingStatisticsMenu
> - (InteractivePlayer &, UI::UniqueWindow::Registry &);
> + BuildingStatisticsMenu(InteractivePlayer&, UI::UniqueWindow::Registry&);
>
> void think() override;
> - void draw(RenderTarget &) override;
> void update();
> + bool handle_key(bool const down, SDL_Keysym const code) override;
>
> private:
> - bool compare_building_size(uint32_t rowa, uint32_t rowb);
> -
> - InteractivePlayer & iplayer() const;
> - enum JumpTargets {
> - PrevOwned, NextOwned,
> - PrevConstruction, NextConstruction,
> - PrevUnproductive, NextUnproductive
> - };
> -
> - UI::Table<uintptr_t const> m_table;
> - UI::ProgressBar m_progbar;
> - UI::Textarea m_total_productivity_label;
> - UI::Textarea m_owned_label;
> - UI::Textarea m_owned;
> - UI::Textarea m_in_build_label;
> - UI::Textarea m_in_build;
> - UI::Textarea m_unproductive_label;
> - uint32_t m_anim;
> - uint32_t m_lastupdate;
> - uint32_t m_end_of_table_y;
> - UI::Button * m_btn[6];
> - int32_t m_last_building_index;
> - uint32_t m_last_table_index;
> -
> - void clicked_help();
> - void clicked_jump(JumpTargets);
> - void table_changed(uint32_t);
> - int32_t validate_pointer(int32_t *, int32_t);
> + /// Which building state to jump through
> + enum class JumpTarget {kOwned, kConstruction, kUnproductive};
> +
> + /// Adds a button for the building type belonging to the id and descr to the tab.
> + /// Returns true when a new row needs to be created.
> + bool add_button(
> + BuildingIndex id, const BuildingDescr& descr, UI::Box& tab, UI::Box& row, int* column);
> +
> + /// Jumps to the next / previous appropriate building
> + void jump_building(BuildingIndex id, JumpTarget target);
> +
> + /// Helper function for jump_building to go round robin
> + int32_t validate_pointer(int32_t*, int32_t);
> +
> + InteractivePlayer& iplayer() const;
> +
> + /// Reverses the direction that buildings get jumped through
> + bool is_shift_pressed_;
> +
> + /// UI tabs
> + UI::TabPanel tabs_;
> + UI::Box small_tab_;
> + UI::Box medium_tab_;
> + UI::Box big_tab_;
> + UI::Box mines_tab_;
> + UI::Box ports_tab_;
> +
> + /// Button with building icon
> + std::vector<UI::Button*> building_buttons_;
> + /// Button with owned / under construction buildings
> + std::vector<UI::Button*> owned_buttons_;
> + /// Button with buildings' productivity
> + std::vector<UI::Button*> productivity_buttons_;
> + /// The last building that was jumped to
> + int32_t last_building_index_;
> + /// The type of last building that was jumped to
> + BuildingIndex last_building_type_;
> + /// The last time the information in this Panel got updated
> + uint32_t lastupdate_;
> };
>
> #endif // end of include guard: WL_WUI_BUILDING_STATISTICS_MENU_H
>
> === modified file 'src/wui/interactive_player.cc'
> --- src/wui/interactive_player.cc 2015-05-10 10:59:28 +0000
> +++ src/wui/interactive_player.cc 2015-05-13 06:02:16 +0000
> @@ -336,6 +336,14 @@
> set_display_flag(dfShowCensus, !get_display_flag(dfShowCensus));
> return true;
>
> + case SDLK_b:
> + if (m_mainm_windows.building_stats.window == nullptr) {
> + new BuildingStatisticsMenu(*this, m_mainm_windows.building_stats);
> + } else {
> + m_mainm_windows.building_stats.toggle();
> + }
> + return true;
> +
> case SDLK_s:
> if (code.mod & (KMOD_LCTRL | KMOD_RCTRL))
> new GameMainMenuSaveGame(*this, m_mainm_windows.savegame);
>
> === modified file 'txts/README.lua'
> --- txts/README.lua 2014-12-28 16:45:37 +0000
> +++ txts/README.lua 2015-05-13 06:02:16 +0000
> @@ -67,6 +67,7 @@
> .. _"S: toggles statistics" .. "<br>"
> .. _"I: toggles stock inventory" .. "<br>"
> .. _"O: toggles objectives" .. "<br>"
> +.. _"B: toggles building statistics" .. "<br>"
> .. _"F: toggles fullscreen (if supported by the OS)" .. "<br>"
> .. _"Home: centers main mapview on starting location" .. "<br>"
> .. _"(CTRL+) 0-9: Remember and go to previously remembered locations" .. "<br>"
>
--
https://code.launchpad.net/~widelands-dev/widelands/bug-1399621/+merge/258843
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/bug-1399621 into lp:widelands.
References