Merge lp:~widelands-dev/widelands/smaller_building_statistics into lp:widelands
- smaller_building_statistics
- Merge into trunk
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 |
Related bugs: |
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.
bunnybot (widelandsofficial) wrote : | # |
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 ;-) ?
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.
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.
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.
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.
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:/
Klaus Halfmann (klaus-halfmann) wrote : | # |
fetched it again, no idea if I have time at the weekend.
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_
* I need a another map _with_ seafaring, my current one does not allow this ....
* I was unable to trigger BuildingStatist
no idea why this was never called. Gun: any idea?
Klaus Halfmann (klaus-halfmann) wrote : | # |
I testplayed this now on a seafaring Map:
* I was unable to reach the following lies of code:
* BuildingStatist
...
if (descr.type() == MapObjectType:
descr.type() == MapObjectType:
return false;
// I think this can never be reached I can not build a forign building
// A dismantled site cannot be reached
* BuildingStatist
...
if (building_
set_current_
} 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
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
1 | === modified file 'data/tribes/buildings/warehouses/atlanteans/port/init.lua' |
2 | --- data/tribes/buildings/warehouses/atlanteans/port/init.lua 2017-09-02 19:53:03 +0000 |
3 | +++ data/tribes/buildings/warehouses/atlanteans/port/init.lua 2018-04-12 05:33:14 +0000 |
4 | @@ -8,6 +8,7 @@ |
5 | helptext_script = dirname .. "helptexts.lua", |
6 | icon = dirname .. "menu.png", |
7 | size = "port", |
8 | + needs_seafaring = true, |
9 | |
10 | buildcost = { |
11 | log = 3, |
12 | |
13 | === modified file 'data/tribes/buildings/warehouses/barbarians/port/init.lua' |
14 | --- data/tribes/buildings/warehouses/barbarians/port/init.lua 2017-09-02 19:53:03 +0000 |
15 | +++ data/tribes/buildings/warehouses/barbarians/port/init.lua 2018-04-12 05:33:14 +0000 |
16 | @@ -8,6 +8,7 @@ |
17 | helptext_script = dirname .. "helptexts.lua", |
18 | icon = dirname .. "menu.png", |
19 | size = "port", |
20 | + needs_seafaring = true, |
21 | |
22 | buildcost = { |
23 | log = 3, |
24 | |
25 | === modified file 'data/tribes/buildings/warehouses/empire/port/init.lua' |
26 | --- data/tribes/buildings/warehouses/empire/port/init.lua 2017-09-02 19:53:03 +0000 |
27 | +++ data/tribes/buildings/warehouses/empire/port/init.lua 2018-04-12 05:33:14 +0000 |
28 | @@ -8,6 +8,7 @@ |
29 | helptext_script = dirname .. "helptexts.lua", |
30 | icon = dirname .. "menu.png", |
31 | size = "port", |
32 | + needs_seafaring = true, |
33 | |
34 | buildcost = { |
35 | log = 3, |
36 | |
37 | === modified file 'data/tribes/buildings/warehouses/frisians/port/init.lua' |
38 | --- data/tribes/buildings/warehouses/frisians/port/init.lua 2018-02-16 14:53:04 +0000 |
39 | +++ data/tribes/buildings/warehouses/frisians/port/init.lua 2018-04-12 05:33:14 +0000 |
40 | @@ -8,6 +8,7 @@ |
41 | helptext_script = dirname .. "helptexts.lua", |
42 | icon = dirname .. "menu.png", |
43 | size = "port", |
44 | + needs_seafaring = true, |
45 | |
46 | buildcost = { |
47 | brick = 6, |
48 | |
49 | === modified file 'src/ui_basic/tabpanel.cc' |
50 | --- src/ui_basic/tabpanel.cc 2018-04-07 16:59:00 +0000 |
51 | +++ src/ui_basic/tabpanel.cc 2018-04-12 05:33:14 +0000 |
52 | @@ -225,6 +225,9 @@ |
53 | } |
54 | |
55 | bool TabPanel::remove_last_tab(const std::string& tabname) { |
56 | + if (tabs_.empty()) { |
57 | + return false; |
58 | + } |
59 | if (tabs_.back()->get_name() == tabname) { |
60 | tabs_.pop_back(); |
61 | if (active_ > tabs_.size() - 1) { |
62 | |
63 | === modified file 'src/wui/building_statistics_menu.cc' |
64 | --- src/wui/building_statistics_menu.cc 2018-04-07 16:59:00 +0000 |
65 | +++ src/wui/building_statistics_menu.cc 2018-04-12 05:33:14 +0000 |
66 | @@ -39,9 +39,7 @@ |
67 | constexpr int kButtonRowHeight = kButtonHeight + kMargin; |
68 | constexpr int kLabelHeight = 18; |
69 | constexpr int kLabelFontSize = 12; |
70 | -constexpr int kTabHeight = 35 + 5 * (kBuildGridCellHeight + kLabelHeight + kLabelHeight); |
71 | constexpr int32_t kWindowWidth = kColumns * kBuildGridCellWidth; |
72 | -constexpr int32_t kWindowHeight = kTabHeight + kMargin + 4 * kButtonRowHeight; |
73 | |
74 | constexpr int32_t kUpdateTimeInGametimeMs = 1000; // 1 second, gametime |
75 | |
76 | @@ -63,7 +61,7 @@ |
77 | "building_statistics", |
78 | ®istry, |
79 | kWindowWidth, |
80 | - kWindowHeight, |
81 | + 100, |
82 | _("Building Statistics")), |
83 | tab_panel_(this, g_gr->images().get("images/ui_basic/but1.png")), |
84 | navigation_panel_(this, 0, 0, kWindowWidth, 4 * kButtonRowHeight), |
85 | @@ -118,119 +116,12 @@ |
86 | "", |
87 | UI::Align::kRight), |
88 | low_production_(33), |
89 | - has_selection_(false) { |
90 | - |
91 | - for (int i = 0; i < kNoOfBuildingTabs; ++i) { |
92 | - row_counters_[i] = 0; |
93 | - tabs_[i] = new UI::Box(&tab_panel_, 0, 0, UI::Box::Vertical); |
94 | - } |
95 | - |
96 | - tab_panel_.add("building_stats_small", |
97 | - g_gr->images().get("images/wui/fieldaction/menu_tab_buildsmall.png"), |
98 | - tabs_[BuildingTab::Small], _("Small buildings")); |
99 | - tab_panel_.add("building_stats_medium", |
100 | - g_gr->images().get("images/wui/fieldaction/menu_tab_buildmedium.png"), |
101 | - tabs_[BuildingTab::Medium], _("Medium buildings")); |
102 | - tab_panel_.add("building_stats_big", |
103 | - g_gr->images().get("images/wui/fieldaction/menu_tab_buildbig.png"), |
104 | - tabs_[BuildingTab::Big], _("Big buildings")); |
105 | - tab_panel_.add("building_stats_mines", |
106 | - g_gr->images().get("images/wui/fieldaction/menu_tab_buildmine.png"), |
107 | - tabs_[BuildingTab::Mines], _("Mines")); |
108 | - |
109 | - // Only show the ports tab for seafaring maps |
110 | - if (iplayer().game().map().allows_seafaring()) { |
111 | - tab_panel_.add("building_stats_ports", |
112 | - g_gr->images().get("images/wui/fieldaction/menu_tab_buildport.png"), |
113 | - tabs_[BuildingTab::Ports], _("Ports")); |
114 | - } |
115 | - |
116 | - const DescriptionIndex nr_buildings = parent.egbase().tribes().nrbuildings(); |
117 | - building_buttons_ = std::vector<UI::Button*>(nr_buildings); |
118 | - owned_labels_ = std::vector<UI::Textarea*>(nr_buildings); |
119 | - productivity_labels_ = std::vector<UI::Textarea*>(nr_buildings); |
120 | - |
121 | - // Column counters |
122 | - int columns[kNoOfBuildingTabs] = {0, 0, 0, 0, 0}; |
123 | - |
124 | - // Row containers |
125 | - UI::Box* rows[kNoOfBuildingTabs]; |
126 | - for (int i = 0; i < kNoOfBuildingTabs; ++i) { |
127 | - rows[i] = new UI::Box(tabs_[i], 0, 0, UI::Box::Horizontal); |
128 | - } |
129 | - |
130 | - // We want to add player tribe's buildings in correct order |
131 | - const TribeDescr& tribe = iplayer().player().tribe(); |
132 | - std::vector<DescriptionIndex> buildings_to_add; |
133 | - for (DescriptionIndex index : tribe.buildings()) { |
134 | - // Only add headquarter types that are owned by player. |
135 | - const BuildingDescr& descr = *tribe.get_building_descr(index); |
136 | - const Widelands::Player& player = iplayer().player(); |
137 | - if (descr.is_buildable() || descr.is_enhanced() || |
138 | - !player.get_building_statistics(index).empty()) { |
139 | - buildings_to_add.push_back(index); |
140 | - } |
141 | - } |
142 | - |
143 | - // We want to add other tribes' militarysites on the bottom |
144 | - for (DescriptionIndex index = 0; index < nr_buildings; ++index) { |
145 | - const BuildingDescr& descr = *parent.egbase().tribes().get_building_descr(index); |
146 | - if (descr.type() == MapObjectType::MILITARYSITE && !tribe.has_building(index)) { |
147 | - buildings_to_add.push_back(index); |
148 | - } |
149 | - } |
150 | - |
151 | - for (DescriptionIndex id : buildings_to_add) { |
152 | - const BuildingDescr& descr = *tribe.get_building_descr(id); |
153 | - |
154 | - if (descr.type() != MapObjectType::CONSTRUCTIONSITE && |
155 | - descr.type() != MapObjectType::DISMANTLESITE) { |
156 | - if (descr.get_ismine()) { |
157 | - if (add_button(id, descr, BuildingTab::Mines, *rows[BuildingTab::Mines], |
158 | - &columns[BuildingTab::Mines])) { |
159 | - rows[BuildingTab::Mines] = |
160 | - new UI::Box(tabs_[BuildingTab::Mines], 0, 0, UI::Box::Horizontal); |
161 | - } |
162 | - } else if (descr.get_isport()) { |
163 | - if (add_button(id, descr, BuildingTab::Ports, *rows[BuildingTab::Ports], |
164 | - &columns[BuildingTab::Ports])) { |
165 | - rows[BuildingTab::Ports] = |
166 | - new UI::Box(tabs_[BuildingTab::Ports], 0, 0, UI::Box::Horizontal); |
167 | - } |
168 | - } else { |
169 | - switch (descr.get_size()) { |
170 | - case BaseImmovable::SMALL: |
171 | - if (add_button(id, descr, BuildingTab::Small, *rows[BuildingTab::Small], |
172 | - &columns[BuildingTab::Small])) { |
173 | - rows[BuildingTab::Small] = |
174 | - new UI::Box(tabs_[BuildingTab::Small], 0, 0, UI::Box::Horizontal); |
175 | - } |
176 | - break; |
177 | - case BaseImmovable::MEDIUM: |
178 | - if (add_button(id, descr, BuildingTab::Medium, *rows[BuildingTab::Medium], |
179 | - &columns[BuildingTab::Medium])) { |
180 | - rows[BuildingTab::Medium] = |
181 | - new UI::Box(tabs_[BuildingTab::Medium], 0, 0, UI::Box::Horizontal); |
182 | - } |
183 | - break; |
184 | - case BaseImmovable::BIG: |
185 | - if (add_button(id, descr, BuildingTab::Big, *rows[BuildingTab::Big], |
186 | - &columns[BuildingTab::Big])) { |
187 | - rows[BuildingTab::Big] = |
188 | - new UI::Box(tabs_[BuildingTab::Big], 0, 0, UI::Box::Horizontal); |
189 | - } |
190 | - break; |
191 | - default: |
192 | - throw wexception( |
193 | - "Building statictics: Found building without a size: %s", descr.name().c_str()); |
194 | - } |
195 | - } |
196 | - } |
197 | - } |
198 | - |
199 | - for (int i = 0; i < kNoOfBuildingTabs; ++i) { |
200 | - tabs_[i]->add(rows[i]); |
201 | - } |
202 | + has_selection_(false), |
203 | + nr_building_types_(parent.egbase().tribes().nrbuildings()) { |
204 | + |
205 | + building_buttons_ = std::vector<UI::Button*>(nr_building_types_); |
206 | + owned_labels_ = std::vector<UI::Textarea*>(nr_building_types_); |
207 | + productivity_labels_ = std::vector<UI::Textarea*>(nr_building_types_); |
208 | |
209 | set_label_font(&owned_label_); |
210 | set_label_font(&construction_label_); |
211 | @@ -306,7 +197,7 @@ |
212 | unproductive_percent_.cancel.connect( |
213 | boost::bind(&BuildingStatisticsMenu::low_production_reset_focus, boost::ref(*this))); |
214 | |
215 | - update(); |
216 | + init(); |
217 | } |
218 | |
219 | BuildingStatisticsMenu::~BuildingStatisticsMenu() { |
220 | @@ -315,6 +206,189 @@ |
221 | productivity_labels_.clear(); |
222 | } |
223 | |
224 | +void BuildingStatisticsMenu::reset() { |
225 | + update(); // In case a building got removed, make sure to deselect it first |
226 | + |
227 | + const int last_selected_tab = tab_assignments_[tab_panel_.active()]; |
228 | + |
229 | + tab_panel_.remove_last_tab("building_stats_ports"); |
230 | + tab_panel_.remove_last_tab("building_stats_mines"); |
231 | + tab_panel_.remove_last_tab("building_stats_big"); |
232 | + tab_panel_.remove_last_tab("building_stats_medium"); |
233 | + tab_panel_.remove_last_tab("building_stats_small"); |
234 | + |
235 | + // Clean state if buildings disappear from list |
236 | + building_buttons_.clear(); |
237 | + building_buttons_.resize(nr_building_types_); |
238 | + owned_labels_.clear(); |
239 | + owned_labels_.resize(nr_building_types_); |
240 | + productivity_labels_.clear(); |
241 | + productivity_labels_.resize(nr_building_types_); |
242 | + |
243 | + // Ensure that defunct buttons disappear |
244 | + for (int tab_index = 0; tab_index < kNoOfBuildingTabs; ++tab_index) { |
245 | + if (tabs_[tab_index] != nullptr) { |
246 | + tabs_[tab_index]->die(); |
247 | + } |
248 | + } |
249 | + |
250 | + init(last_selected_tab); |
251 | + |
252 | + // Reset navigator |
253 | + building_name_.set_text(""); |
254 | + if (has_selection_) { |
255 | + if (building_buttons_[current_building_type_] != nullptr) { |
256 | + set_current_building_type(current_building_type_); |
257 | + } else { |
258 | + has_selection_ = false; |
259 | + } |
260 | + } |
261 | +} |
262 | + |
263 | +void BuildingStatisticsMenu::init(int last_selected_tab) { |
264 | + // We want to add player tribe's buildings in correct order |
265 | + const Widelands::Player& player = iplayer().player(); |
266 | + const TribeDescr& tribe = player.tribe(); |
267 | + const bool map_allows_seafaring = iplayer().game().map().allows_seafaring(); |
268 | + std::vector<DescriptionIndex> buildings_to_add[kNoOfBuildingTabs]; |
269 | + // Add the player's own tribe's buildings. |
270 | + for (DescriptionIndex index : tribe.buildings()) { |
271 | + if (own_building_is_valid(player, index, map_allows_seafaring)) { |
272 | + buildings_to_add[find_tab_for_building(*tribe.get_building_descr(index))].push_back(index); |
273 | + } |
274 | + } |
275 | + |
276 | + // We want to add other tribes' buildings on the bottom. Only add the ones that the player owns. |
277 | + for (DescriptionIndex index = 0; index < nr_building_types_; ++index) { |
278 | + if (foreign_tribe_building_is_valid(player, index)) { |
279 | + buildings_to_add[find_tab_for_building(*tribe.get_building_descr(index))].push_back(index); |
280 | + } |
281 | + } |
282 | + |
283 | + // Now create the tab contents and add the building buttons |
284 | + int row_counters[kNoOfBuildingTabs]; |
285 | + for (int tab_index = 0; tab_index < kNoOfBuildingTabs; ++tab_index) { |
286 | + int current_column = 0; |
287 | + tabs_[tab_index] = new UI::Box(&tab_panel_, 0, 0, UI::Box::Vertical); |
288 | + UI::Box* row = new UI::Box(tabs_[tab_index], 0, 0, UI::Box::Horizontal); |
289 | + row_counters[tab_index] = 0; |
290 | + |
291 | + for (const Widelands::DescriptionIndex id : buildings_to_add[tab_index]) { |
292 | + const BuildingDescr& descr = *iplayer().egbase().tribes().get_building_descr(id); |
293 | + add_button(id, descr, row); |
294 | + ++current_column; |
295 | + if (current_column == 1) { |
296 | + ++row_counters[tab_index]; |
297 | + } else if (current_column == kColumns) { |
298 | + tabs_[tab_index]->add(row, UI::Box::Resizing::kFullSize); |
299 | + tabs_[tab_index]->add_space(6); |
300 | + row = new UI::Box(tabs_[tab_index], 0, 0, UI::Box::Horizontal); |
301 | + current_column = 0; |
302 | + } |
303 | + } |
304 | + // Add final row |
305 | + if (current_column != 0) { |
306 | + tabs_[tab_index]->add(row, UI::Box::Resizing::kFullSize); |
307 | + } |
308 | + } |
309 | + |
310 | + // Show the tabs that have buttons on them |
311 | + int tab_counter = 0; |
312 | + auto add_tab = [this, row_counters, &tab_counter, last_selected_tab]( |
313 | + int tab_index, const std::string& name, const std::string& image, const std::string& descr) { |
314 | + if (row_counters[tab_index] > 0) { |
315 | + tab_panel_.add(name, g_gr->images().get(image), tabs_[tab_index], descr); |
316 | + if (last_selected_tab == tab_index) { |
317 | + tab_panel_.activate(tab_counter); |
318 | + } |
319 | + tab_assignments_[tab_counter] = tab_index; |
320 | + row_counters_[tab_counter] = row_counters[tab_index]; |
321 | + ++tab_counter; |
322 | + } |
323 | + }; |
324 | + add_tab(BuildingTab::Small, "building_stats_small", |
325 | + "images/wui/fieldaction/menu_tab_buildsmall.png", _("Small buildings")); |
326 | + add_tab(BuildingTab::Medium, "building_stats_medium", |
327 | + "images/wui/fieldaction/menu_tab_buildmedium.png", _("Medium buildings")); |
328 | + add_tab(BuildingTab::Big, "building_stats_big", "images/wui/fieldaction/menu_tab_buildbig.png", |
329 | + _("Big buildings")); |
330 | + add_tab(BuildingTab::Mines, "building_stats_mines", |
331 | + "images/wui/fieldaction/menu_tab_buildmine.png", _("Mines")); |
332 | + add_tab(BuildingTab::Ports, "building_stats_ports", |
333 | + "images/wui/fieldaction/menu_tab_buildport.png", _("Ports")); |
334 | + |
335 | + update(); |
336 | +} |
337 | + |
338 | +bool BuildingStatisticsMenu::own_building_is_valid(const Widelands::Player& player, Widelands::DescriptionIndex index, bool map_allows_seafaring) const { |
339 | + const BuildingDescr& descr = *player.tribe().get_building_descr(index); |
340 | + // Skip seafaring buildings if not needed |
341 | + if (descr.needs_seafaring() && !map_allows_seafaring && |
342 | + player.get_building_statistics(index).empty()) { |
343 | + return false; |
344 | + } |
345 | + if (descr.type() == MapObjectType::CONSTRUCTIONSITE || |
346 | + descr.type() == MapObjectType::DISMANTLESITE) { |
347 | + return false; |
348 | + } |
349 | + // Only add allowed buildings or buildings that are owned by the player. |
350 | + if ((player.is_building_type_allowed(index) && (descr.is_buildable() || descr.is_enhanced())) || |
351 | + !player.get_building_statistics(index).empty()) { |
352 | + return true; |
353 | + } |
354 | + return false; |
355 | +} |
356 | + |
357 | +bool BuildingStatisticsMenu::foreign_tribe_building_is_valid( |
358 | + const Widelands::Player& player, Widelands::DescriptionIndex index) const { |
359 | + if (!player.tribe().has_building(index) && !player.get_building_statistics(index).empty()) { |
360 | + const BuildingDescr& descr = *iplayer().egbase().tribes().get_building_descr(index); |
361 | + if (descr.type() == MapObjectType::CONSTRUCTIONSITE || |
362 | + descr.type() == MapObjectType::DISMANTLESITE) { |
363 | + return false; |
364 | + } |
365 | + return true; |
366 | + } |
367 | + return false; |
368 | +} |
369 | + |
370 | +int BuildingStatisticsMenu::find_tab_for_building(const Widelands::BuildingDescr& descr) const { |
371 | + assert(descr.type() != MapObjectType::CONSTRUCTIONSITE); |
372 | + assert(descr.type() != MapObjectType::DISMANTLESITE); |
373 | + if (descr.get_ismine()) { |
374 | + return BuildingTab::Mines; |
375 | + } else if (descr.get_isport()) { |
376 | + return BuildingTab::Ports; |
377 | + } else { |
378 | + switch (descr.get_size()) { |
379 | + case BaseImmovable::SMALL: |
380 | + return BuildingTab::Small; |
381 | + case BaseImmovable::MEDIUM: |
382 | + return BuildingTab::Medium; |
383 | + case BaseImmovable::BIG: |
384 | + return BuildingTab::Big; |
385 | + default: |
386 | + throw wexception( |
387 | + "Building statictics: Found building without a size: %s", descr.name().c_str()); |
388 | + } |
389 | + } |
390 | + NEVER_HERE(); |
391 | +} |
392 | + |
393 | +void BuildingStatisticsMenu::update_building_list() { |
394 | + const Widelands::Player& player = iplayer().player(); |
395 | + const bool map_allows_seafaring = iplayer().game().map().allows_seafaring(); |
396 | + for (DescriptionIndex index = 0; index < nr_building_types_; ++index) { |
397 | + const bool should_have_this_building = |
398 | + own_building_is_valid(player, index, map_allows_seafaring) || foreign_tribe_building_is_valid(player, index); |
399 | + const bool has_this_building = building_buttons_[index] != nullptr; |
400 | + if (should_have_this_building != has_this_building) { |
401 | + reset(); |
402 | + return; |
403 | + } |
404 | + } |
405 | +} |
406 | + |
407 | /** |
408 | * Adds 3 buttons per building type. |
409 | * |
410 | @@ -322,10 +396,10 @@ |
411 | * - Buildings owned, steps through constructionsites |
412 | * - Productivity, steps though buildings with low productivity and stopped buildings |
413 | */ |
414 | -bool BuildingStatisticsMenu::add_button( |
415 | - DescriptionIndex id, const BuildingDescr& descr, int tab_index, UI::Box& row, int* column) { |
416 | - |
417 | - UI::Box* button_box = new UI::Box(&row, 0, 0, UI::Box::Vertical); |
418 | +void BuildingStatisticsMenu::add_button(DescriptionIndex id, |
419 | + const BuildingDescr& descr, |
420 | + UI::Box* row) { |
421 | + UI::Box* button_box = new UI::Box(row, 0, 0, UI::Box::Vertical); |
422 | building_buttons_[id] = new UI::Button( |
423 | button_box, (boost::format("building_button%s") % id).str(), 0, 0, kBuildGridCellWidth, |
424 | kBuildGridCellHeight, g_gr->images().get("images/ui_basic/but1.png"), |
425 | @@ -347,25 +421,10 @@ |
426 | productivity_labels_[id]->set_fixed_width(kBuildGridCellWidth); |
427 | button_box->add(productivity_labels_[id]); |
428 | |
429 | - row.add(button_box); |
430 | + row->add(button_box); |
431 | |
432 | building_buttons_[id]->sigclicked.connect( |
433 | boost::bind(&BuildingStatisticsMenu::set_current_building_type, boost::ref(*this), id)); |
434 | - |
435 | - // For dynamic window height |
436 | - if (*column == 0) { |
437 | - ++row_counters_[tab_index]; |
438 | - } |
439 | - |
440 | - // Check if the row is full |
441 | - ++*column; |
442 | - if (*column == kColumns) { |
443 | - tabs_[tab_index]->add(&row); |
444 | - tabs_[tab_index]->add_space(6); |
445 | - *column = 0; |
446 | - return true; |
447 | - } |
448 | - return false; |
449 | } |
450 | |
451 | void BuildingStatisticsMenu::jump_building(JumpTarget target, bool reverse) { |
452 | @@ -496,28 +555,30 @@ |
453 | * Update this statistic |
454 | */ |
455 | void BuildingStatisticsMenu::think() { |
456 | + // Update statistics |
457 | + const int32_t gametime = iplayer().game().get_gametime(); |
458 | + |
459 | + if (was_minimized_ || (gametime - lastupdate_) > kUpdateTimeInGametimeMs) { |
460 | + update_building_list(); |
461 | + update(); |
462 | + lastupdate_ = gametime; |
463 | + } |
464 | + // Make sure we don't have a delay with displaying labels when we restore the window. |
465 | + was_minimized_ = is_minimal(); |
466 | + |
467 | // Adjust height to current tab |
468 | if (is_minimal()) { |
469 | tab_panel_.set_size(0, 0); |
470 | } else { |
471 | - int tab_height = |
472 | + const int tab_height = |
473 | 35 + |
474 | - row_counters_[tab_panel_.active()] * (kBuildGridCellHeight + kLabelHeight + kLabelHeight); |
475 | + row_counters_[tab_panel_.active()] * (kBuildGridCellHeight + kLabelHeight + kLabelHeight) + |
476 | + kMargin; |
477 | tab_panel_.set_size(kWindowWidth, tab_height); |
478 | set_size( |
479 | - get_w(), tab_height + kMargin + 4 * kButtonRowHeight + get_tborder() + get_bborder()); |
480 | + get_w(), tab_height + kMargin + navigation_panel_.get_h() + get_tborder() + get_bborder()); |
481 | navigation_panel_.set_pos(Vector2i(0, tab_height + kMargin)); |
482 | } |
483 | - |
484 | - // Update statistics |
485 | - const int32_t gametime = iplayer().game().get_gametime(); |
486 | - |
487 | - if (was_minimized_ || (gametime - lastupdate_) > kUpdateTimeInGametimeMs) { |
488 | - update(); |
489 | - lastupdate_ = gametime; |
490 | - } |
491 | - // Make sure we don't have a delay with displaying labels when we restore the window. |
492 | - was_minimized_ = is_minimal(); |
493 | } |
494 | |
495 | /* |
496 | @@ -540,7 +601,6 @@ |
497 | void BuildingStatisticsMenu::update() { |
498 | const Player& player = iplayer().player(); |
499 | const TribeDescr& tribe = player.tribe(); |
500 | - const DescriptionIndex nr_buildings = iplayer().egbase().tribes().nrbuildings(); |
501 | |
502 | owned_label_.set_visible(false); |
503 | no_owned_label_.set_visible(false); |
504 | @@ -558,7 +618,7 @@ |
505 | navigation_buttons_[NavigationButton::NextUnproductive]->set_visible(false); |
506 | navigation_buttons_[NavigationButton::PrevUnproductive]->set_visible(false); |
507 | |
508 | - for (DescriptionIndex id = 0; id < nr_buildings; ++id) { |
509 | + for (DescriptionIndex id = 0; id < nr_building_types_; ++id) { |
510 | const BuildingDescr& building = *tribe.get_building_descr(id); |
511 | if (building_buttons_[id] == nullptr) { |
512 | continue; |
513 | @@ -676,7 +736,9 @@ |
514 | } |
515 | |
516 | std::string owned_text; |
517 | - if (player.tribe().has_building(id) && (building.is_buildable() || building.is_enhanced())) { |
518 | + const bool can_construct_this_building = player.tribe().has_building(id) && |
519 | + (building.is_buildable() || building.is_enhanced()); |
520 | + if (can_construct_this_building) { |
521 | /** TRANSLATORS: Buildings: owned / under construction */ |
522 | owned_text = (boost::format(_("%1%/%2%")) % nr_owned % nr_build).str(); |
523 | } else { |
524 | @@ -694,7 +756,7 @@ |
525 | no_owned_label_.set_visible(true); |
526 | navigation_buttons_[NavigationButton::NextOwned]->set_visible(true); |
527 | navigation_buttons_[NavigationButton::PrevOwned]->set_visible(true); |
528 | - if (player.tribe().has_building(id) && building.is_buildable()) { |
529 | + if (can_construct_this_building) { |
530 | no_construction_label_.set_text(nr_build > 0 ? std::to_string(nr_build) : ""); |
531 | navigation_buttons_[NavigationButton::NextConstruction]->set_enabled(nr_build > 0); |
532 | navigation_buttons_[NavigationButton::PrevConstruction]->set_enabled(nr_build > 0); |
533 | |
534 | === modified file 'src/wui/building_statistics_menu.h' |
535 | --- src/wui/building_statistics_menu.h 2018-04-07 16:59:00 +0000 |
536 | +++ src/wui/building_statistics_menu.h 2018-04-12 05:33:14 +0000 |
537 | @@ -46,6 +46,8 @@ |
538 | ~BuildingStatisticsMenu() override; |
539 | |
540 | void think() override; |
541 | + |
542 | + /// Update state of current building buttons |
543 | void update(); |
544 | |
545 | private: |
546 | @@ -65,13 +67,25 @@ |
547 | NextUnproductive |
548 | }; |
549 | |
550 | + /// Initialize the buttons |
551 | + void reset(); |
552 | + void init(int last_selected_tab = 0); |
553 | + |
554 | + /// Whether a building that is used by the player's tribe should be added |
555 | + bool own_building_is_valid(const Widelands::Player& player, Widelands::DescriptionIndex index, bool map_allows_seafaring) const; |
556 | + /// Whether a building that isn't used by the player's tribe should be added |
557 | + bool foreign_tribe_building_is_valid(const Widelands::Player& player, Widelands::DescriptionIndex index) const; |
558 | + /// Determine which tab a building button should end up on, according to building size etc. |
559 | + int find_tab_for_building(const Widelands::BuildingDescr& descr) const; |
560 | + |
561 | + /// If the buildings that should be shown have changes, update the list and reinitialize |
562 | + void update_building_list(); |
563 | + |
564 | /// Adds a button for the building type belonging to the id and descr to the tab. |
565 | /// Returns true when a new row needs to be created. |
566 | - bool add_button(Widelands::DescriptionIndex id, |
567 | + void add_button(Widelands::DescriptionIndex id, |
568 | const Widelands::BuildingDescr& descr, |
569 | - int tab_index, |
570 | - UI::Box& row, |
571 | - int* column); |
572 | + UI::Box* row); |
573 | |
574 | /// Jumps to the next / previous appropriate building |
575 | void jump_building(JumpTarget target, bool reverse); |
576 | @@ -95,7 +109,10 @@ |
577 | /// UI tabs |
578 | UI::TabPanel tab_panel_; |
579 | UI::Box* tabs_[kNoOfBuildingTabs]; |
580 | + /// How many button rows each tab has |
581 | int row_counters_[kNoOfBuildingTabs]; |
582 | + /// We can have gaps in the tab sequence, so we need to map the indices for remembering the last selected tab |
583 | + int tab_assignments_[kNoOfBuildingTabs]; |
584 | |
585 | /// Button with building icon |
586 | std::vector<UI::Button*> building_buttons_; |
587 | @@ -134,6 +151,9 @@ |
588 | |
589 | /// Whether a building has been selected |
590 | bool has_selection_; |
591 | + |
592 | + /// The total number of building types available for all the tribes |
593 | + const Widelands::DescriptionIndex nr_building_types_; |
594 | }; |
595 | |
596 | #endif // end of include guard: WL_WUI_BUILDING_STATISTICS_MENU_H |
Continuous integration builds have changed state:
Travis build 3357. State: passed. Details: https:/ /travis- ci.org/ widelands/ widelands/ builds/ 363552376. /ci.appveyor. com/project/ widelands- dev/widelands/ build/_ widelands_ dev_widelands_ smaller_ building_ statistics- 3163.
Appveyor build 3163. State: success. Details: https:/