Merge lp:~widelands-dev/widelands/smaller_building_statistics into lp:widelands

Proposed by GunChleoc
Status: Merged
Merged at revision: 8656
Proposed branch: lp:~widelands-dev/widelands/smaller_building_statistics
Merge into: lp:widelands
Diff against target: 596 lines (+247/-158)
7 files modified
data/tribes/buildings/warehouses/atlanteans/port/init.lua (+1/-0)
data/tribes/buildings/warehouses/barbarians/port/init.lua (+1/-0)
data/tribes/buildings/warehouses/empire/port/init.lua (+1/-0)
data/tribes/buildings/warehouses/frisians/port/init.lua (+1/-0)
src/ui_basic/tabpanel.cc (+3/-0)
src/wui/building_statistics_menu.cc (+216/-154)
src/wui/building_statistics_menu.h (+24/-4)
To merge this branch: bzr merge lp:~widelands-dev/widelands/smaller_building_statistics
Reviewer Review Type Date Requested Status
Klaus Halfmann compile, revied, debug for coverage, testplay Approve
GunChleoc Needs Resubmitting
Review via email: mp+342828@code.launchpad.net

Commit message

Building Statistics now only show relevant buildings
- Military sites not belonging to the tribe are omitted, unless the payer currently owns one
- Seafaring and allowed buildings are dynamically checked
- Show "under construction" navigation for buildings being enhanced
- Added "needs_seafaring" to port buildings

Description of the change

Fixes the attached bug.

Since the Frisians were added, the building statistics got too big due to all the military sites - the navigation became impossible to reach on 800x600 resolution without moving the window around. So, I have implemented a dynamic approach that will only show allowed and currently owned buildings.

To post a comment you must log in.
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 3357. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/363552376.
Appveyor build 3163. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_smaller_building_statistics-3163.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

One question inline, will take a closer look later.

just brached this and will have a look.

Not sure who will be the payer for the other tribes military sites ;-) ?

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Some more commetns inline, I think this deserves some time in the debugger.
Mostly for me to better understand the widelands internal structures.

Maybe this will make things slower, Not sure about this, lets seee.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Thanks for the review :)

And you were right about the efficiency concerns, the seafaring check is causing a slowdown. I have reduced it to be checked once every 2 minutes.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I have changed my mind about the seafaring check - since this is so expensive, we should generally only recalculate it on map changes. I'll create another branch for it, to be merged before this branch.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Mhh, scripts might want to add seafaring later in some scenario.
Hopefully this will not break such scripts.

Anyway, I do not have that much time today for a debugging session,
lets see what I can do perhaps next weekend.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I know - I have taken care of it. Branch is ready; I'll put it up for review as soon as Launchpad has finished parsing it.

https://code.launchpad.net/~widelands-dev/widelands/allows_seafaring_performance

review: Needs Resubmitting
Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

fetched it again, no idea if I have time at the weekend.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

I did some testplaying with a debugger now and gained some coverage of that code:
 * Everything worked as expected so far.
 * The Handling of the forward / backward buttons has room for improvement:
  * no need so use large switch blocks -> call the repective function directly.
  * Maybe I can do some refactoring there, later.
 * I could not trigger foreign_tribe_building_is_valid, yet, no Enemy t conquer found so far :-)
 * I need a another map _with_ seafaring, my current one does not allow this ....
 * I was unable to trigger BuildingStatisticsMenu::reset()
   no idea why this was never called. Gun: any idea?

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

I testplayed this now on a seafaring Map:
 * I was unable to reach the following lies of code:
  * BuildingStatisticsMenu::foreign_tribe_building_is_valid()
    ...
    if (descr.type() == MapObjectType::CONSTRUCTIONSITE ||
 descr.type() == MapObjectType::DISMANTLESITE) {
 return false;
    // I think this can never be reached I can not build a forign building
    // A dismantled site cannot be reached
  * BuildingStatisticsMenu::reset()
     ...
     if (building_buttons_[current_building_type_] != nullptr) {
 set_current_building_type(current_building_type_); // no idea what this shall be
     } else {
 * I found that some missing soldiers Arrows where incorrect for a foreign military building.

 * I played on a lot of different resolutions

Despite these Issues this can go in:

@bunnybot merge

review: Approve (compile, revied, debug for coverage, testplay)
Revision history for this message
GunChleoc (gunchleoc) wrote :

You trigger those by conquering a foreign military site and then again by destroying it. I ran a setup on Golden Peninsula where I gave the opponent the "Village" starting condition. so that I could easily conquer something.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'data/tribes/buildings/warehouses/atlanteans/port/init.lua'
--- data/tribes/buildings/warehouses/atlanteans/port/init.lua 2017-09-02 19:53:03 +0000
+++ data/tribes/buildings/warehouses/atlanteans/port/init.lua 2018-04-12 05:33:14 +0000
@@ -8,6 +8,7 @@
8 helptext_script = dirname .. "helptexts.lua",8 helptext_script = dirname .. "helptexts.lua",
9 icon = dirname .. "menu.png",9 icon = dirname .. "menu.png",
10 size = "port",10 size = "port",
11 needs_seafaring = true,
1112
12 buildcost = {13 buildcost = {
13 log = 3,14 log = 3,
1415
=== modified file 'data/tribes/buildings/warehouses/barbarians/port/init.lua'
--- data/tribes/buildings/warehouses/barbarians/port/init.lua 2017-09-02 19:53:03 +0000
+++ data/tribes/buildings/warehouses/barbarians/port/init.lua 2018-04-12 05:33:14 +0000
@@ -8,6 +8,7 @@
8 helptext_script = dirname .. "helptexts.lua",8 helptext_script = dirname .. "helptexts.lua",
9 icon = dirname .. "menu.png",9 icon = dirname .. "menu.png",
10 size = "port",10 size = "port",
11 needs_seafaring = true,
1112
12 buildcost = {13 buildcost = {
13 log = 3,14 log = 3,
1415
=== modified file 'data/tribes/buildings/warehouses/empire/port/init.lua'
--- data/tribes/buildings/warehouses/empire/port/init.lua 2017-09-02 19:53:03 +0000
+++ data/tribes/buildings/warehouses/empire/port/init.lua 2018-04-12 05:33:14 +0000
@@ -8,6 +8,7 @@
8 helptext_script = dirname .. "helptexts.lua",8 helptext_script = dirname .. "helptexts.lua",
9 icon = dirname .. "menu.png",9 icon = dirname .. "menu.png",
10 size = "port",10 size = "port",
11 needs_seafaring = true,
1112
12 buildcost = {13 buildcost = {
13 log = 3,14 log = 3,
1415
=== modified file 'data/tribes/buildings/warehouses/frisians/port/init.lua'
--- data/tribes/buildings/warehouses/frisians/port/init.lua 2018-02-16 14:53:04 +0000
+++ data/tribes/buildings/warehouses/frisians/port/init.lua 2018-04-12 05:33:14 +0000
@@ -8,6 +8,7 @@
8 helptext_script = dirname .. "helptexts.lua",8 helptext_script = dirname .. "helptexts.lua",
9 icon = dirname .. "menu.png",9 icon = dirname .. "menu.png",
10 size = "port",10 size = "port",
11 needs_seafaring = true,
1112
12 buildcost = {13 buildcost = {
13 brick = 6,14 brick = 6,
1415
=== modified file 'src/ui_basic/tabpanel.cc'
--- src/ui_basic/tabpanel.cc 2018-04-07 16:59:00 +0000
+++ src/ui_basic/tabpanel.cc 2018-04-12 05:33:14 +0000
@@ -225,6 +225,9 @@
225}225}
226226
227bool TabPanel::remove_last_tab(const std::string& tabname) {227bool TabPanel::remove_last_tab(const std::string& tabname) {
228 if (tabs_.empty()) {
229 return false;
230 }
228 if (tabs_.back()->get_name() == tabname) {231 if (tabs_.back()->get_name() == tabname) {
229 tabs_.pop_back();232 tabs_.pop_back();
230 if (active_ > tabs_.size() - 1) {233 if (active_ > tabs_.size() - 1) {
231234
=== modified file 'src/wui/building_statistics_menu.cc'
--- src/wui/building_statistics_menu.cc 2018-04-07 16:59:00 +0000
+++ src/wui/building_statistics_menu.cc 2018-04-12 05:33:14 +0000
@@ -39,9 +39,7 @@
39constexpr int kButtonRowHeight = kButtonHeight + kMargin;39constexpr int kButtonRowHeight = kButtonHeight + kMargin;
40constexpr int kLabelHeight = 18;40constexpr int kLabelHeight = 18;
41constexpr int kLabelFontSize = 12;41constexpr int kLabelFontSize = 12;
42constexpr int kTabHeight = 35 + 5 * (kBuildGridCellHeight + kLabelHeight + kLabelHeight);
43constexpr int32_t kWindowWidth = kColumns * kBuildGridCellWidth;42constexpr int32_t kWindowWidth = kColumns * kBuildGridCellWidth;
44constexpr int32_t kWindowHeight = kTabHeight + kMargin + 4 * kButtonRowHeight;
4543
46constexpr int32_t kUpdateTimeInGametimeMs = 1000; // 1 second, gametime44constexpr int32_t kUpdateTimeInGametimeMs = 1000; // 1 second, gametime
4745
@@ -63,7 +61,7 @@
63 "building_statistics",61 "building_statistics",
64 &registry,62 &registry,
65 kWindowWidth,63 kWindowWidth,
66 kWindowHeight,64 100,
67 _("Building Statistics")),65 _("Building Statistics")),
68 tab_panel_(this, g_gr->images().get("images/ui_basic/but1.png")),66 tab_panel_(this, g_gr->images().get("images/ui_basic/but1.png")),
69 navigation_panel_(this, 0, 0, kWindowWidth, 4 * kButtonRowHeight),67 navigation_panel_(this, 0, 0, kWindowWidth, 4 * kButtonRowHeight),
@@ -118,119 +116,12 @@
118 "",116 "",
119 UI::Align::kRight),117 UI::Align::kRight),
120 low_production_(33),118 low_production_(33),
121 has_selection_(false) {119 has_selection_(false),
122120 nr_building_types_(parent.egbase().tribes().nrbuildings()) {
123 for (int i = 0; i < kNoOfBuildingTabs; ++i) {121
124 row_counters_[i] = 0;122 building_buttons_ = std::vector<UI::Button*>(nr_building_types_);
125 tabs_[i] = new UI::Box(&tab_panel_, 0, 0, UI::Box::Vertical);123 owned_labels_ = std::vector<UI::Textarea*>(nr_building_types_);
126 }124 productivity_labels_ = std::vector<UI::Textarea*>(nr_building_types_);
127
128 tab_panel_.add("building_stats_small",
129 g_gr->images().get("images/wui/fieldaction/menu_tab_buildsmall.png"),
130 tabs_[BuildingTab::Small], _("Small buildings"));
131 tab_panel_.add("building_stats_medium",
132 g_gr->images().get("images/wui/fieldaction/menu_tab_buildmedium.png"),
133 tabs_[BuildingTab::Medium], _("Medium buildings"));
134 tab_panel_.add("building_stats_big",
135 g_gr->images().get("images/wui/fieldaction/menu_tab_buildbig.png"),
136 tabs_[BuildingTab::Big], _("Big buildings"));
137 tab_panel_.add("building_stats_mines",
138 g_gr->images().get("images/wui/fieldaction/menu_tab_buildmine.png"),
139 tabs_[BuildingTab::Mines], _("Mines"));
140
141 // Only show the ports tab for seafaring maps
142 if (iplayer().game().map().allows_seafaring()) {
143 tab_panel_.add("building_stats_ports",
144 g_gr->images().get("images/wui/fieldaction/menu_tab_buildport.png"),
145 tabs_[BuildingTab::Ports], _("Ports"));
146 }
147
148 const DescriptionIndex nr_buildings = parent.egbase().tribes().nrbuildings();
149 building_buttons_ = std::vector<UI::Button*>(nr_buildings);
150 owned_labels_ = std::vector<UI::Textarea*>(nr_buildings);
151 productivity_labels_ = std::vector<UI::Textarea*>(nr_buildings);
152
153 // Column counters
154 int columns[kNoOfBuildingTabs] = {0, 0, 0, 0, 0};
155
156 // Row containers
157 UI::Box* rows[kNoOfBuildingTabs];
158 for (int i = 0; i < kNoOfBuildingTabs; ++i) {
159 rows[i] = new UI::Box(tabs_[i], 0, 0, UI::Box::Horizontal);
160 }
161
162 // We want to add player tribe's buildings in correct order
163 const TribeDescr& tribe = iplayer().player().tribe();
164 std::vector<DescriptionIndex> buildings_to_add;
165 for (DescriptionIndex index : tribe.buildings()) {
166 // Only add headquarter types that are owned by player.
167 const BuildingDescr& descr = *tribe.get_building_descr(index);
168 const Widelands::Player& player = iplayer().player();
169 if (descr.is_buildable() || descr.is_enhanced() ||
170 !player.get_building_statistics(index).empty()) {
171 buildings_to_add.push_back(index);
172 }
173 }
174
175 // We want to add other tribes' militarysites on the bottom
176 for (DescriptionIndex index = 0; index < nr_buildings; ++index) {
177 const BuildingDescr& descr = *parent.egbase().tribes().get_building_descr(index);
178 if (descr.type() == MapObjectType::MILITARYSITE && !tribe.has_building(index)) {
179 buildings_to_add.push_back(index);
180 }
181 }
182
183 for (DescriptionIndex id : buildings_to_add) {
184 const BuildingDescr& descr = *tribe.get_building_descr(id);
185
186 if (descr.type() != MapObjectType::CONSTRUCTIONSITE &&
187 descr.type() != MapObjectType::DISMANTLESITE) {
188 if (descr.get_ismine()) {
189 if (add_button(id, descr, BuildingTab::Mines, *rows[BuildingTab::Mines],
190 &columns[BuildingTab::Mines])) {
191 rows[BuildingTab::Mines] =
192 new UI::Box(tabs_[BuildingTab::Mines], 0, 0, UI::Box::Horizontal);
193 }
194 } else if (descr.get_isport()) {
195 if (add_button(id, descr, BuildingTab::Ports, *rows[BuildingTab::Ports],
196 &columns[BuildingTab::Ports])) {
197 rows[BuildingTab::Ports] =
198 new UI::Box(tabs_[BuildingTab::Ports], 0, 0, UI::Box::Horizontal);
199 }
200 } else {
201 switch (descr.get_size()) {
202 case BaseImmovable::SMALL:
203 if (add_button(id, descr, BuildingTab::Small, *rows[BuildingTab::Small],
204 &columns[BuildingTab::Small])) {
205 rows[BuildingTab::Small] =
206 new UI::Box(tabs_[BuildingTab::Small], 0, 0, UI::Box::Horizontal);
207 }
208 break;
209 case BaseImmovable::MEDIUM:
210 if (add_button(id, descr, BuildingTab::Medium, *rows[BuildingTab::Medium],
211 &columns[BuildingTab::Medium])) {
212 rows[BuildingTab::Medium] =
213 new UI::Box(tabs_[BuildingTab::Medium], 0, 0, UI::Box::Horizontal);
214 }
215 break;
216 case BaseImmovable::BIG:
217 if (add_button(id, descr, BuildingTab::Big, *rows[BuildingTab::Big],
218 &columns[BuildingTab::Big])) {
219 rows[BuildingTab::Big] =
220 new UI::Box(tabs_[BuildingTab::Big], 0, 0, UI::Box::Horizontal);
221 }
222 break;
223 default:
224 throw wexception(
225 "Building statictics: Found building without a size: %s", descr.name().c_str());
226 }
227 }
228 }
229 }
230
231 for (int i = 0; i < kNoOfBuildingTabs; ++i) {
232 tabs_[i]->add(rows[i]);
233 }
234125
235 set_label_font(&owned_label_);126 set_label_font(&owned_label_);
236 set_label_font(&construction_label_);127 set_label_font(&construction_label_);
@@ -306,7 +197,7 @@
306 unproductive_percent_.cancel.connect(197 unproductive_percent_.cancel.connect(
307 boost::bind(&BuildingStatisticsMenu::low_production_reset_focus, boost::ref(*this)));198 boost::bind(&BuildingStatisticsMenu::low_production_reset_focus, boost::ref(*this)));
308199
309 update();200 init();
310}201}
311202
312BuildingStatisticsMenu::~BuildingStatisticsMenu() {203BuildingStatisticsMenu::~BuildingStatisticsMenu() {
@@ -315,6 +206,189 @@
315 productivity_labels_.clear();206 productivity_labels_.clear();
316}207}
317208
209void BuildingStatisticsMenu::reset() {
210 update(); // In case a building got removed, make sure to deselect it first
211
212 const int last_selected_tab = tab_assignments_[tab_panel_.active()];
213
214 tab_panel_.remove_last_tab("building_stats_ports");
215 tab_panel_.remove_last_tab("building_stats_mines");
216 tab_panel_.remove_last_tab("building_stats_big");
217 tab_panel_.remove_last_tab("building_stats_medium");
218 tab_panel_.remove_last_tab("building_stats_small");
219
220 // Clean state if buildings disappear from list
221 building_buttons_.clear();
222 building_buttons_.resize(nr_building_types_);
223 owned_labels_.clear();
224 owned_labels_.resize(nr_building_types_);
225 productivity_labels_.clear();
226 productivity_labels_.resize(nr_building_types_);
227
228 // Ensure that defunct buttons disappear
229 for (int tab_index = 0; tab_index < kNoOfBuildingTabs; ++tab_index) {
230 if (tabs_[tab_index] != nullptr) {
231 tabs_[tab_index]->die();
232 }
233 }
234
235 init(last_selected_tab);
236
237 // Reset navigator
238 building_name_.set_text("");
239 if (has_selection_) {
240 if (building_buttons_[current_building_type_] != nullptr) {
241 set_current_building_type(current_building_type_);
242 } else {
243 has_selection_ = false;
244 }
245 }
246}
247
248void BuildingStatisticsMenu::init(int last_selected_tab) {
249 // We want to add player tribe's buildings in correct order
250 const Widelands::Player& player = iplayer().player();
251 const TribeDescr& tribe = player.tribe();
252 const bool map_allows_seafaring = iplayer().game().map().allows_seafaring();
253 std::vector<DescriptionIndex> buildings_to_add[kNoOfBuildingTabs];
254 // Add the player's own tribe's buildings.
255 for (DescriptionIndex index : tribe.buildings()) {
256 if (own_building_is_valid(player, index, map_allows_seafaring)) {
257 buildings_to_add[find_tab_for_building(*tribe.get_building_descr(index))].push_back(index);
258 }
259 }
260
261 // We want to add other tribes' buildings on the bottom. Only add the ones that the player owns.
262 for (DescriptionIndex index = 0; index < nr_building_types_; ++index) {
263 if (foreign_tribe_building_is_valid(player, index)) {
264 buildings_to_add[find_tab_for_building(*tribe.get_building_descr(index))].push_back(index);
265 }
266 }
267
268 // Now create the tab contents and add the building buttons
269 int row_counters[kNoOfBuildingTabs];
270 for (int tab_index = 0; tab_index < kNoOfBuildingTabs; ++tab_index) {
271 int current_column = 0;
272 tabs_[tab_index] = new UI::Box(&tab_panel_, 0, 0, UI::Box::Vertical);
273 UI::Box* row = new UI::Box(tabs_[tab_index], 0, 0, UI::Box::Horizontal);
274 row_counters[tab_index] = 0;
275
276 for (const Widelands::DescriptionIndex id : buildings_to_add[tab_index]) {
277 const BuildingDescr& descr = *iplayer().egbase().tribes().get_building_descr(id);
278 add_button(id, descr, row);
279 ++current_column;
280 if (current_column == 1) {
281 ++row_counters[tab_index];
282 } else if (current_column == kColumns) {
283 tabs_[tab_index]->add(row, UI::Box::Resizing::kFullSize);
284 tabs_[tab_index]->add_space(6);
285 row = new UI::Box(tabs_[tab_index], 0, 0, UI::Box::Horizontal);
286 current_column = 0;
287 }
288 }
289 // Add final row
290 if (current_column != 0) {
291 tabs_[tab_index]->add(row, UI::Box::Resizing::kFullSize);
292 }
293 }
294
295 // Show the tabs that have buttons on them
296 int tab_counter = 0;
297 auto add_tab = [this, row_counters, &tab_counter, last_selected_tab](
298 int tab_index, const std::string& name, const std::string& image, const std::string& descr) {
299 if (row_counters[tab_index] > 0) {
300 tab_panel_.add(name, g_gr->images().get(image), tabs_[tab_index], descr);
301 if (last_selected_tab == tab_index) {
302 tab_panel_.activate(tab_counter);
303 }
304 tab_assignments_[tab_counter] = tab_index;
305 row_counters_[tab_counter] = row_counters[tab_index];
306 ++tab_counter;
307 }
308 };
309 add_tab(BuildingTab::Small, "building_stats_small",
310 "images/wui/fieldaction/menu_tab_buildsmall.png", _("Small buildings"));
311 add_tab(BuildingTab::Medium, "building_stats_medium",
312 "images/wui/fieldaction/menu_tab_buildmedium.png", _("Medium buildings"));
313 add_tab(BuildingTab::Big, "building_stats_big", "images/wui/fieldaction/menu_tab_buildbig.png",
314 _("Big buildings"));
315 add_tab(BuildingTab::Mines, "building_stats_mines",
316 "images/wui/fieldaction/menu_tab_buildmine.png", _("Mines"));
317 add_tab(BuildingTab::Ports, "building_stats_ports",
318 "images/wui/fieldaction/menu_tab_buildport.png", _("Ports"));
319
320 update();
321}
322
323bool BuildingStatisticsMenu::own_building_is_valid(const Widelands::Player& player, Widelands::DescriptionIndex index, bool map_allows_seafaring) const {
324 const BuildingDescr& descr = *player.tribe().get_building_descr(index);
325 // Skip seafaring buildings if not needed
326 if (descr.needs_seafaring() && !map_allows_seafaring &&
327 player.get_building_statistics(index).empty()) {
328 return false;
329 }
330 if (descr.type() == MapObjectType::CONSTRUCTIONSITE ||
331 descr.type() == MapObjectType::DISMANTLESITE) {
332 return false;
333 }
334 // Only add allowed buildings or buildings that are owned by the player.
335 if ((player.is_building_type_allowed(index) && (descr.is_buildable() || descr.is_enhanced())) ||
336 !player.get_building_statistics(index).empty()) {
337 return true;
338 }
339 return false;
340}
341
342bool BuildingStatisticsMenu::foreign_tribe_building_is_valid(
343 const Widelands::Player& player, Widelands::DescriptionIndex index) const {
344 if (!player.tribe().has_building(index) && !player.get_building_statistics(index).empty()) {
345 const BuildingDescr& descr = *iplayer().egbase().tribes().get_building_descr(index);
346 if (descr.type() == MapObjectType::CONSTRUCTIONSITE ||
347 descr.type() == MapObjectType::DISMANTLESITE) {
348 return false;
349 }
350 return true;
351 }
352 return false;
353}
354
355int BuildingStatisticsMenu::find_tab_for_building(const Widelands::BuildingDescr& descr) const {
356 assert(descr.type() != MapObjectType::CONSTRUCTIONSITE);
357 assert(descr.type() != MapObjectType::DISMANTLESITE);
358 if (descr.get_ismine()) {
359 return BuildingTab::Mines;
360 } else if (descr.get_isport()) {
361 return BuildingTab::Ports;
362 } else {
363 switch (descr.get_size()) {
364 case BaseImmovable::SMALL:
365 return BuildingTab::Small;
366 case BaseImmovable::MEDIUM:
367 return BuildingTab::Medium;
368 case BaseImmovable::BIG:
369 return BuildingTab::Big;
370 default:
371 throw wexception(
372 "Building statictics: Found building without a size: %s", descr.name().c_str());
373 }
374 }
375 NEVER_HERE();
376}
377
378void BuildingStatisticsMenu::update_building_list() {
379 const Widelands::Player& player = iplayer().player();
380 const bool map_allows_seafaring = iplayer().game().map().allows_seafaring();
381 for (DescriptionIndex index = 0; index < nr_building_types_; ++index) {
382 const bool should_have_this_building =
383 own_building_is_valid(player, index, map_allows_seafaring) || foreign_tribe_building_is_valid(player, index);
384 const bool has_this_building = building_buttons_[index] != nullptr;
385 if (should_have_this_building != has_this_building) {
386 reset();
387 return;
388 }
389 }
390}
391
318/**392/**
319 * Adds 3 buttons per building type.393 * Adds 3 buttons per building type.
320 *394 *
@@ -322,10 +396,10 @@
322 * - Buildings owned, steps through constructionsites396 * - Buildings owned, steps through constructionsites
323 * - Productivity, steps though buildings with low productivity and stopped buildings397 * - Productivity, steps though buildings with low productivity and stopped buildings
324 */398 */
325bool BuildingStatisticsMenu::add_button(399void BuildingStatisticsMenu::add_button(DescriptionIndex id,
326 DescriptionIndex id, const BuildingDescr& descr, int tab_index, UI::Box& row, int* column) {400 const BuildingDescr& descr,
327401 UI::Box* row) {
328 UI::Box* button_box = new UI::Box(&row, 0, 0, UI::Box::Vertical);402 UI::Box* button_box = new UI::Box(row, 0, 0, UI::Box::Vertical);
329 building_buttons_[id] = new UI::Button(403 building_buttons_[id] = new UI::Button(
330 button_box, (boost::format("building_button%s") % id).str(), 0, 0, kBuildGridCellWidth,404 button_box, (boost::format("building_button%s") % id).str(), 0, 0, kBuildGridCellWidth,
331 kBuildGridCellHeight, g_gr->images().get("images/ui_basic/but1.png"),405 kBuildGridCellHeight, g_gr->images().get("images/ui_basic/but1.png"),
@@ -347,25 +421,10 @@
347 productivity_labels_[id]->set_fixed_width(kBuildGridCellWidth);421 productivity_labels_[id]->set_fixed_width(kBuildGridCellWidth);
348 button_box->add(productivity_labels_[id]);422 button_box->add(productivity_labels_[id]);
349423
350 row.add(button_box);424 row->add(button_box);
351425
352 building_buttons_[id]->sigclicked.connect(426 building_buttons_[id]->sigclicked.connect(
353 boost::bind(&BuildingStatisticsMenu::set_current_building_type, boost::ref(*this), id));427 boost::bind(&BuildingStatisticsMenu::set_current_building_type, boost::ref(*this), id));
354
355 // For dynamic window height
356 if (*column == 0) {
357 ++row_counters_[tab_index];
358 }
359
360 // Check if the row is full
361 ++*column;
362 if (*column == kColumns) {
363 tabs_[tab_index]->add(&row);
364 tabs_[tab_index]->add_space(6);
365 *column = 0;
366 return true;
367 }
368 return false;
369}428}
370429
371void BuildingStatisticsMenu::jump_building(JumpTarget target, bool reverse) {430void BuildingStatisticsMenu::jump_building(JumpTarget target, bool reverse) {
@@ -496,28 +555,30 @@
496 * Update this statistic555 * Update this statistic
497 */556 */
498void BuildingStatisticsMenu::think() {557void BuildingStatisticsMenu::think() {
558 // Update statistics
559 const int32_t gametime = iplayer().game().get_gametime();
560
561 if (was_minimized_ || (gametime - lastupdate_) > kUpdateTimeInGametimeMs) {
562 update_building_list();
563 update();
564 lastupdate_ = gametime;
565 }
566 // Make sure we don't have a delay with displaying labels when we restore the window.
567 was_minimized_ = is_minimal();
568
499 // Adjust height to current tab569 // Adjust height to current tab
500 if (is_minimal()) {570 if (is_minimal()) {
501 tab_panel_.set_size(0, 0);571 tab_panel_.set_size(0, 0);
502 } else {572 } else {
503 int tab_height =573 const int tab_height =
504 35 +574 35 +
505 row_counters_[tab_panel_.active()] * (kBuildGridCellHeight + kLabelHeight + kLabelHeight);575 row_counters_[tab_panel_.active()] * (kBuildGridCellHeight + kLabelHeight + kLabelHeight) +
576 kMargin;
506 tab_panel_.set_size(kWindowWidth, tab_height);577 tab_panel_.set_size(kWindowWidth, tab_height);
507 set_size(578 set_size(
508 get_w(), tab_height + kMargin + 4 * kButtonRowHeight + get_tborder() + get_bborder());579 get_w(), tab_height + kMargin + navigation_panel_.get_h() + get_tborder() + get_bborder());
509 navigation_panel_.set_pos(Vector2i(0, tab_height + kMargin));580 navigation_panel_.set_pos(Vector2i(0, tab_height + kMargin));
510 }581 }
511
512 // Update statistics
513 const int32_t gametime = iplayer().game().get_gametime();
514
515 if (was_minimized_ || (gametime - lastupdate_) > kUpdateTimeInGametimeMs) {
516 update();
517 lastupdate_ = gametime;
518 }
519 // Make sure we don't have a delay with displaying labels when we restore the window.
520 was_minimized_ = is_minimal();
521}582}
522583
523/*584/*
@@ -540,7 +601,6 @@
540void BuildingStatisticsMenu::update() {601void BuildingStatisticsMenu::update() {
541 const Player& player = iplayer().player();602 const Player& player = iplayer().player();
542 const TribeDescr& tribe = player.tribe();603 const TribeDescr& tribe = player.tribe();
543 const DescriptionIndex nr_buildings = iplayer().egbase().tribes().nrbuildings();
544604
545 owned_label_.set_visible(false);605 owned_label_.set_visible(false);
546 no_owned_label_.set_visible(false);606 no_owned_label_.set_visible(false);
@@ -558,7 +618,7 @@
558 navigation_buttons_[NavigationButton::NextUnproductive]->set_visible(false);618 navigation_buttons_[NavigationButton::NextUnproductive]->set_visible(false);
559 navigation_buttons_[NavigationButton::PrevUnproductive]->set_visible(false);619 navigation_buttons_[NavigationButton::PrevUnproductive]->set_visible(false);
560620
561 for (DescriptionIndex id = 0; id < nr_buildings; ++id) {621 for (DescriptionIndex id = 0; id < nr_building_types_; ++id) {
562 const BuildingDescr& building = *tribe.get_building_descr(id);622 const BuildingDescr& building = *tribe.get_building_descr(id);
563 if (building_buttons_[id] == nullptr) {623 if (building_buttons_[id] == nullptr) {
564 continue;624 continue;
@@ -676,7 +736,9 @@
676 }736 }
677737
678 std::string owned_text;738 std::string owned_text;
679 if (player.tribe().has_building(id) && (building.is_buildable() || building.is_enhanced())) {739 const bool can_construct_this_building = player.tribe().has_building(id) &&
740 (building.is_buildable() || building.is_enhanced());
741 if (can_construct_this_building) {
680 /** TRANSLATORS: Buildings: owned / under construction */742 /** TRANSLATORS: Buildings: owned / under construction */
681 owned_text = (boost::format(_("%1%/%2%")) % nr_owned % nr_build).str();743 owned_text = (boost::format(_("%1%/%2%")) % nr_owned % nr_build).str();
682 } else {744 } else {
@@ -694,7 +756,7 @@
694 no_owned_label_.set_visible(true);756 no_owned_label_.set_visible(true);
695 navigation_buttons_[NavigationButton::NextOwned]->set_visible(true);757 navigation_buttons_[NavigationButton::NextOwned]->set_visible(true);
696 navigation_buttons_[NavigationButton::PrevOwned]->set_visible(true);758 navigation_buttons_[NavigationButton::PrevOwned]->set_visible(true);
697 if (player.tribe().has_building(id) && building.is_buildable()) {759 if (can_construct_this_building) {
698 no_construction_label_.set_text(nr_build > 0 ? std::to_string(nr_build) : "");760 no_construction_label_.set_text(nr_build > 0 ? std::to_string(nr_build) : "");
699 navigation_buttons_[NavigationButton::NextConstruction]->set_enabled(nr_build > 0);761 navigation_buttons_[NavigationButton::NextConstruction]->set_enabled(nr_build > 0);
700 navigation_buttons_[NavigationButton::PrevConstruction]->set_enabled(nr_build > 0);762 navigation_buttons_[NavigationButton::PrevConstruction]->set_enabled(nr_build > 0);
701763
=== modified file 'src/wui/building_statistics_menu.h'
--- src/wui/building_statistics_menu.h 2018-04-07 16:59:00 +0000
+++ src/wui/building_statistics_menu.h 2018-04-12 05:33:14 +0000
@@ -46,6 +46,8 @@
46 ~BuildingStatisticsMenu() override;46 ~BuildingStatisticsMenu() override;
4747
48 void think() override;48 void think() override;
49
50 /// Update state of current building buttons
49 void update();51 void update();
5052
51private:53private:
@@ -65,13 +67,25 @@
65 NextUnproductive67 NextUnproductive
66 };68 };
6769
70 /// Initialize the buttons
71 void reset();
72 void init(int last_selected_tab = 0);
73
74 /// Whether a building that is used by the player's tribe should be added
75 bool own_building_is_valid(const Widelands::Player& player, Widelands::DescriptionIndex index, bool map_allows_seafaring) const;
76 /// Whether a building that isn't used by the player's tribe should be added
77 bool foreign_tribe_building_is_valid(const Widelands::Player& player, Widelands::DescriptionIndex index) const;
78 /// Determine which tab a building button should end up on, according to building size etc.
79 int find_tab_for_building(const Widelands::BuildingDescr& descr) const;
80
81 /// If the buildings that should be shown have changes, update the list and reinitialize
82 void update_building_list();
83
68 /// Adds a button for the building type belonging to the id and descr to the tab.84 /// Adds a button for the building type belonging to the id and descr to the tab.
69 /// Returns true when a new row needs to be created.85 /// Returns true when a new row needs to be created.
70 bool add_button(Widelands::DescriptionIndex id,86 void add_button(Widelands::DescriptionIndex id,
71 const Widelands::BuildingDescr& descr,87 const Widelands::BuildingDescr& descr,
72 int tab_index,88 UI::Box* row);
73 UI::Box& row,
74 int* column);
7589
76 /// Jumps to the next / previous appropriate building90 /// Jumps to the next / previous appropriate building
77 void jump_building(JumpTarget target, bool reverse);91 void jump_building(JumpTarget target, bool reverse);
@@ -95,7 +109,10 @@
95 /// UI tabs109 /// UI tabs
96 UI::TabPanel tab_panel_;110 UI::TabPanel tab_panel_;
97 UI::Box* tabs_[kNoOfBuildingTabs];111 UI::Box* tabs_[kNoOfBuildingTabs];
112 /// How many button rows each tab has
98 int row_counters_[kNoOfBuildingTabs];113 int row_counters_[kNoOfBuildingTabs];
114 /// We can have gaps in the tab sequence, so we need to map the indices for remembering the last selected tab
115 int tab_assignments_[kNoOfBuildingTabs];
99116
100 /// Button with building icon117 /// Button with building icon
101 std::vector<UI::Button*> building_buttons_;118 std::vector<UI::Button*> building_buttons_;
@@ -134,6 +151,9 @@
134151
135 /// Whether a building has been selected152 /// Whether a building has been selected
136 bool has_selection_;153 bool has_selection_;
154
155 /// The total number of building types available for all the tribes
156 const Widelands::DescriptionIndex nr_building_types_;
137};157};
138158
139#endif // end of include guard: WL_WUI_BUILDING_STATISTICS_MENU_H159#endif // end of include guard: WL_WUI_BUILDING_STATISTICS_MENU_H

Subscribers

People subscribed via source and target branches

to status/vote changes: