widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #04009
[Merge] lp:~widelands-dev/widelands/bug-1399621 into lp:widelands
GunChleoc has proposed merging lp:~widelands-dev/widelands/bug-1399621 into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
Related bugs:
Bug #849705 in widelands: "Add a column for "stopped" buildings in building statistics"
https://bugs.launchpad.net/widelands/+bug/849705
Bug #1399621 in widelands: "Building Statistics Window Redesign"
https://bugs.launchpad.net/widelands/+bug/1399621
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/bug-1399621/+merge/258843
The Building Statistics window now uses a grid layout with tabs, analogous to flagaction.
Added "b" hotkey to toggle the window.
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/bug-1399621 into lp:widelands.
=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc 2015-03-01 09:21:20 +0000
+++ src/wlapplication.cc 2015-05-12 08:35:35 +0000
@@ -550,6 +550,7 @@
SDL_Event ev;
while (poll_event(ev)) {
switch (ev.type) {
+ case SDL_KEYUP:
case SDL_KEYDOWN: {
bool handled = false;
if (cb && cb->key) {
=== 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-12 08:35:35 +0000
@@ -19,494 +19,457 @@
#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, 50)); // 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);
+
+ 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_row)) {
+ ++mines_column;
+ if (mines_column == kColumns) {
+ mines_tab_.add(mines_row, UI::Align_Left);
+ mines_column = 0;
+ mines_row = new UI::Box(&mines_tab_, 0, 0, UI::Box::Horizontal);
+ }
+ }
+ } else if (descr.get_isport()) {
+ if (add_button(id, descr, *ports_row)) {
+ ++ports_column;
+ if (ports_column == kColumns) {
+ ports_tab_.add(ports_row, UI::Align_Left);
+ ports_column = 0;
+ 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_row)) {
+ ++small_column;
+ if (small_column == kColumns) {
+ small_tab_.add(small_row, UI::Align_Left);
+ small_column = 0;
+ small_row = new UI::Box(&small_tab_, 0, 0, UI::Box::Horizontal);
+ }
+ }
+ break;
+ case BaseImmovable::MEDIUM:
+ if (add_button(id, descr, *medium_row)) {
+ ++medium_column;
+ if (medium_column == kColumns) {
+ medium_tab_.add(medium_row, UI::Align_Left);
+ medium_column = 0;
+ medium_row = new UI::Box(&medium_tab_, 0, 0, UI::Box::Horizontal);
+ }
+ }
+ break;
+ case BaseImmovable::BIG:
+ if (add_button(id, descr, *big_row)) {
+ ++big_column;
+ if (big_column == kColumns) {
+ big_tab_.add(big_row, UI::Align_Left);
+ big_column = 0;
+ 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) {
+ // 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(&tab, 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);
+
+ tab.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));
+ return true;
+}
+
+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) {
+ 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-12 08:35:35 +0000
@@ -20,56 +20,66 @@
#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 button was added.
+ bool add_button(BuildingIndex id, const BuildingDescr& descr, UI::Box& tab);
+
+ /// 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-02-14 22:11:44 +0000
+++ src/wui/interactive_player.cc 2015-05-12 08:35:35 +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-12 08:35:35 +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>"
Follow ups