Merge lp:~widelands-dev/widelands/economy-target-profiles into lp:widelands

Proposed by Benedikt Straub
Status: Superseded
Proposed branch: lp:~widelands-dev/widelands/economy-target-profiles
Merge into: lp:widelands
Diff against target: 1603 lines (+937/-169)
17 files modified
data/tribes/economy_profiles/atlanteans (+89/-0)
data/tribes/economy_profiles/barbarians (+81/-0)
data/tribes/economy_profiles/empire (+89/-0)
data/tribes/economy_profiles/frisians (+93/-0)
src/logic/filesystem_constants.h (+2/-0)
src/logic/map_objects/tribes/tribe_descr.cc (+0/-40)
src/logic/map_objects/tribes/tribe_descr.h (+0/-11)
src/logic/map_objects/tribes/tribes.cc (+1/-6)
src/logic/map_objects/tribes/ware_descr.h (+2/-4)
src/logic/playercommand.h (+2/-0)
src/wui/CMakeLists.txt (+2/-0)
src/wui/economy_options_window.cc (+382/-52)
src/wui/economy_options_window.h (+38/-1)
src/wui/inputqueuedisplay.cc (+6/-6)
src/wui/inputqueuedisplay.h (+1/-1)
src/wui/waresdisplay.cc (+121/-46)
src/wui/waresdisplay.h (+28/-2)
To merge this branch: bzr merge lp:~widelands-dev/widelands/economy-target-profiles
Reviewer Review Type Date Requested Status
Widelands Developers Pending
Review via email: mp+366952@code.launchpad.net

This proposal has been superseded by a proposal from 2019-05-06.

Commit message

Users can define and save their own profiles of economy target quantities. Redesigned the economy options menu.

Description of the change

For each tribe, I added two profiles: "Efficiency" is equal to the changes proposed previously, and "Stockpile" is for people who, well, like to stockpile stuff. Additionally there is an unchangeable "Default" profile that resets stuff to the default settings.
To apply a profile, select the profile and the wares you wish to change and click Apply (replaces Reset). Use "Save" to save your current settings as a profile. The save window also allows you to delete profiles.

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

Continuous integration builds have changed state:

Travis build 4886. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/528245915.
Appveyor build 4667. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_economy_target_profiles-4667.

Revision history for this message
GunChleoc (gunchleoc) wrote :

2 Comments. Will do some testing.

Revision history for this message
Benedikt Straub (nordfriese) wrote :

Addressed the reviews: The panels now set hgaps to fill the entire available space, and the profiles are stored in tribes/economy_profiles. I added translation markup to the predefined profiles.

Revision history for this message
GunChleoc (gunchleoc) wrote :

New code LGTM.

I am wondering whether we want to save this as Lua tables? I already have the code finished in the spritesheets branch and could pull it out into a separate branch, since spritesheets aren't ready yet.

Revision history for this message
Benedikt Straub (nordfriese) wrote :

Is there a reason why you prefer LuaTables over profile? Personally I find Profile much easier to use for configs that the user has no reason to manually edit.

Regarding the suggestion in the bug report – A spinbox would make sense, but what value should it display when several wares with different settings are selected?

Revision history for this message
GunChleoc (gunchleoc) wrote :

All the tribe's configuration is in LuaTables, so I guess mainly for consistency - I don't feel strongly about this though.

Good point about the value in the spinbox - I still think we should have the possibility of having steps of 10 though. Maybe fake it with 4 buttons and make them look like the spinbox buttons?

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4901. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/528550026.
Appveyor build 4682. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_economy_target_profiles-4682.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'data/images/ui_basic/scrollbar_down_fast.png'
2Binary files data/images/ui_basic/scrollbar_down_fast.png 1970-01-01 00:00:00 +0000 and data/images/ui_basic/scrollbar_down_fast.png 2019-05-06 13:51:46 +0000 differ
3=== added file 'data/images/ui_basic/scrollbar_up_fast.png'
4Binary files data/images/ui_basic/scrollbar_up_fast.png 1970-01-01 00:00:00 +0000 and data/images/ui_basic/scrollbar_up_fast.png 2019-05-06 13:51:46 +0000 differ
5=== added directory 'data/tribes/economy_profiles'
6=== added file 'data/tribes/economy_profiles/atlanteans'
7--- data/tribes/economy_profiles/atlanteans 1970-01-01 00:00:00 +0000
8+++ data/tribes/economy_profiles/atlanteans 2019-05-06 13:51:46 +0000
9@@ -0,0 +1,89 @@
10+# Automatically created by Widelands bzr9094[economy-target-profiles] (Debug)
11+
12+[Default]
13+0=_"Efficiency"
14+1=_"Stockpile"
15+
16+[0]
17+blackroot_flour="1"
18+atlanteans_bread="20"
19+bread_paddle="0"
20+buckets="0"
21+coal="5"
22+cornmeal="3"
23+diamond="3"
24+fire_tongs="1"
25+fishing_net="2"
26+gold="1"
27+gold_ore="1"
28+gold_thread="0"
29+granite="10"
30+hammer="0"
31+hook_pole="0"
32+hunting_bow="1"
33+iron="5"
34+iron_ore="1"
35+milking_tongs="0"
36+pick="1"
37+planks="1"
38+quartz="3"
39+saw="0"
40+scythe="0"
41+shield_advanced="0"
42+shield_steel="0"
43+shovel="0"
44+smoked_fish="5"
45+smoked_meat="3"
46+spidercloth="5"
47+spider_silk="5"
48+tabard="1"
49+tabard_golden="0"
50+trident_double="0"
51+trident_heavy_double="0"
52+trident_light="1"
53+trident_long="0"
54+trident_steel="0"
55+atlanteans_horse="1"
56+atlanteans_soldier="10"
57+
58+[1]
59+blackroot_flour="20"
60+atlanteans_bread="30"
61+bread_paddle="1"
62+buckets="2"
63+coal="25"
64+cornmeal="20"
65+diamond="10"
66+fire_tongs="1"
67+fishing_net="2"
68+gold="20"
69+gold_ore="15"
70+gold_thread="5"
71+granite="30"
72+hammer="2"
73+hook_pole="1"
74+hunting_bow="1"
75+iron="25"
76+iron_ore="20"
77+milking_tongs="1"
78+pick="3"
79+planks="40"
80+quartz="10"
81+saw="2"
82+scythe="1"
83+shield_advanced="1"
84+shield_steel="1"
85+shovel="2"
86+smoked_fish="40"
87+smoked_meat="25"
88+spidercloth="20"
89+spider_silk="15"
90+tabard="30"
91+tabard_golden="1"
92+trident_double="1"
93+trident_heavy_double="1"
94+trident_light="30"
95+trident_long="1"
96+trident_steel="1"
97+atlanteans_horse="20"
98+atlanteans_soldier="20"
99
100=== added file 'data/tribes/economy_profiles/barbarians'
101--- data/tribes/economy_profiles/barbarians 1970-01-01 00:00:00 +0000
102+++ data/tribes/economy_profiles/barbarians 2019-05-06 13:51:46 +0000
103@@ -0,0 +1,81 @@
104+# Automatically created by Widelands bzr9094[economy-target-profiles] (Debug)
105+
106+[Default]
107+0=_"Efficiency"
108+1=_"Stockpile"
109+
110+[0]
111+ax="1"
112+ax_battle="0"
113+ax_broad="0"
114+ax_bronze="0"
115+ax_sharp="0"
116+ax_warriors="0"
117+beer="0"
118+beer_strong="1"
119+blackwood="40"
120+barbarians_bread="5"
121+bread_paddle="0"
122+cloth="10"
123+coal="20"
124+felling_ax="0"
125+fire_tongs="1"
126+fishing_rod="0"
127+gold="1"
128+gold_ore="1"
129+granite="10"
130+grout="1"
131+hammer="1"
132+helmet="0"
133+helmet_mask="0"
134+helmet_warhelm="0"
135+hunting_spear="0"
136+iron="5"
137+iron_ore="5"
138+kitchen_tools="0"
139+meal="5"
140+pick="1"
141+ration="20"
142+scythe="0"
143+shovel="0"
144+snack="0"
145+barbarians_ox="1"
146+barbarians_soldier="10"
147+
148+[1]
149+ax="30"
150+ax_battle="1"
151+ax_broad="1"
152+ax_bronze="1"
153+ax_sharp="1"
154+ax_warriors="1"
155+beer="15"
156+beer_strong="20"
157+blackwood="45"
158+barbarians_bread="25"
159+bread_paddle="1"
160+cloth="10"
161+coal="25"
162+felling_ax="5"
163+fire_tongs="1"
164+fishing_rod="1"
165+gold="20"
166+gold_ore="15"
167+granite="30"
168+grout="20"
169+hammer="2"
170+helmet="1"
171+helmet_mask="1"
172+helmet_warhelm="1"
173+hunting_spear="1"
174+iron="25"
175+iron_ore="20"
176+kitchen_tools="1"
177+meal="15"
178+pick="2"
179+ration="30"
180+scythe="1"
181+shovel="1"
182+snack="20"
183+barbarians_ox="20"
184+barbarians_soldier="20"
185
186=== added file 'data/tribes/economy_profiles/empire'
187--- data/tribes/economy_profiles/empire 1970-01-01 00:00:00 +0000
188+++ data/tribes/economy_profiles/empire 2019-05-06 13:51:46 +0000
189@@ -0,0 +1,89 @@
190+# Automatically created by Widelands bzr9094[economy-target-profiles] (Debug)
191+
192+[Default]
193+0=_"Efficiency"
194+1=_"Stockpile"
195+
196+[0]
197+armor="1"
198+armor_chain="1"
199+armor_gilded="1"
200+armor_helmet="30"
201+basket="1"
202+beer="1"
203+empire_bread="20"
204+bread_paddle="0"
205+cloth="15"
206+coal="5"
207+felling_ax="0"
208+fire_tongs="1"
209+fishing_rod="0"
210+flour="20"
211+gold="1"
212+gold_ore="1"
213+granite="10"
214+hammer="0"
215+hunting_spear="0"
216+iron="5"
217+iron_ore="3"
218+kitchen_tools="0"
219+marble="30"
220+marble_column="10"
221+meal="5"
222+meat="20"
223+pick="1"
224+planks="1"
225+ration="20"
226+saw="0"
227+scythe="0"
228+shovel="0"
229+spear="1"
230+spear_advanced="1"
231+spear_heavy="1"
232+spear_war="1"
233+spear_wooden="30"
234+wool="10"
235+empire_donkey="1"
236+empire_soldier="10"
237+
238+[1]
239+armor="1"
240+armor_chain="1"
241+armor_gilded="1"
242+armor_helmet="30"
243+basket="1"
244+beer="20"
245+empire_bread="30"
246+bread_paddle="1"
247+cloth="15"
248+coal="25"
249+felling_ax="3"
250+fire_tongs="1"
251+fishing_rod="1"
252+flour="25"
253+gold="20"
254+gold_ore="15"
255+granite="30"
256+hammer="2"
257+hunting_spear="1"
258+iron="25"
259+iron_ore="20"
260+kitchen_tools="1"
261+marble="35"
262+marble_column="15"
263+meal="20"
264+meat="30"
265+pick="2"
266+planks="40"
267+ration="25"
268+saw="1"
269+scythe="1"
270+shovel="1"
271+spear="1"
272+spear_advanced="1"
273+spear_heavy="1"
274+spear_war="1"
275+spear_wooden="30"
276+wool="15"
277+empire_donkey="20"
278+empire_soldier="20"
279
280=== added file 'data/tribes/economy_profiles/frisians'
281--- data/tribes/economy_profiles/frisians 1970-01-01 00:00:00 +0000
282+++ data/tribes/economy_profiles/frisians 2019-05-06 13:51:46 +0000
283@@ -0,0 +1,93 @@
284+# Automatically created by Widelands bzr9093[economy-target-profiles] (Debug)
285+
286+[Default]
287+0=_"Efficiency"
288+1=_"Stockpile"
289+
290+[0]
291+clay="30"
292+brick="40"
293+bread_frisians="20"
294+honey_bread="20"
295+mead="15"
296+fur="10"
297+fur_garment="30"
298+fur_garment_studded="2"
299+fur_garment_golden="2"
300+helmet_golden="2"
301+sword_short="30"
302+sword_long="2"
303+sword_broad="2"
304+sword_double="2"
305+needles="1"
306+basket="1"
307+beer="1"
308+bread_paddle="1"
309+cloth="10"
310+coal="20"
311+felling_ax="0"
312+fire_tongs="1"
313+fish="20"
314+fishing_net="2"
315+gold="1"
316+gold_ore="1"
317+granite="10"
318+hammer="1"
319+helmet="0"
320+hunting_spear="0"
321+iron="5"
322+iron_ore="3"
323+kitchen_tools="0"
324+meal="1"
325+pick="1"
326+ration="20"
327+scythe="0"
328+shovel="0"
329+smoked_fish="20"
330+smoked_meat="10"
331+frisians_reindeer="1"
332+frisians_soldier="10"
333+
334+[1]
335+clay="35"
336+brick="50"
337+bread_frisians="30"
338+honey_bread="30"
339+mead="30"
340+fur="20"
341+fur_garment="30"
342+fur_garment_studded="2"
343+fur_garment_golden="2"
344+helmet_golden="2"
345+sword_short="30"
346+sword_long="2"
347+sword_broad="2"
348+sword_double="2"
349+needles="1"
350+basket="1"
351+beer="30"
352+bread_paddle="1"
353+cloth="10"
354+coal="35"
355+felling_ax="3"
356+fire_tongs="2"
357+fish="40"
358+fishing_net="2"
359+gold="20"
360+gold_ore="15"
361+granite="35"
362+hammer="3"
363+helmet="2"
364+hunting_spear="1"
365+iron="25"
366+iron_ore="20"
367+kitchen_tools="2"
368+meal="10"
369+pick="3"
370+ration="30"
371+scythe="2"
372+shovel="5"
373+smoked_fish="30"
374+smoked_meat="20"
375+frisians_reindeer="20"
376+frisians_soldier="20"
377
378=== modified file 'src/logic/filesystem_constants.h'
379--- src/logic/filesystem_constants.h 2019-04-18 16:50:35 +0000
380+++ src/logic/filesystem_constants.h 2019-05-06 13:51:46 +0000
381@@ -78,4 +78,6 @@
382 /// Filesystem names for config
383 const std::string kConfigFile = "config";
384
385+const std::string kEconomyProfilesDir = "tribes/economy_profiles";
386+
387 #endif // end of include guard: WL_LOGIC_FILESYSTEM_CONSTANTS_H
388
389=== modified file 'src/logic/map_objects/tribes/tribe_descr.cc'
390--- src/logic/map_objects/tribes/tribe_descr.cc 2019-05-04 10:47:44 +0000
391+++ src/logic/map_objects/tribes/tribe_descr.cc 2019-05-06 13:51:46 +0000
392@@ -89,8 +89,6 @@
393 load_roads("busy", &busy_road_paths_);
394
395 items_table = table.get_table("wares_order");
396- wares_order_coords_.resize(tribes_.nrwares());
397- int columnindex = 0;
398 for (const int key : items_table->keys<int>()) {
399 std::vector<DescriptionIndex> column;
400 std::vector<std::string> warenames =
401@@ -104,7 +102,6 @@
402 }
403 wares_.insert(wareindex);
404 column.push_back(wareindex);
405- wares_order_coords_[wareindex] = std::make_pair(columnindex, rowindex);
406 } catch (const WException& e) {
407 throw GameDataError(
408 "Failed adding ware '%s: %s", warenames[rowindex].c_str(), e.what());
409@@ -112,13 +109,10 @@
410 }
411 if (!column.empty()) {
412 wares_order_.push_back(column);
413- ++columnindex;
414 }
415 }
416
417 items_table = table.get_table("workers_order");
418- workers_order_coords_.resize(tribes_.nrworkers());
419- columnindex = 0;
420 for (const int key : items_table->keys<int>()) {
421 std::vector<DescriptionIndex> column;
422 std::vector<std::string> workernames =
423@@ -132,7 +126,6 @@
424 }
425 workers_.insert(workerindex);
426 column.push_back(workerindex);
427- workers_order_coords_[workerindex] = std::make_pair(columnindex, rowindex);
428
429 const WorkerDescr& worker_descr = *tribes_.get_worker_descr(workerindex);
430 if (worker_descr.is_buildable() && worker_descr.buildcost().empty()) {
431@@ -145,7 +138,6 @@
432 }
433 if (!column.empty()) {
434 workers_order_.push_back(column);
435- ++columnindex;
436 }
437 }
438
439@@ -423,38 +415,6 @@
440 return list->second.find(lowest)->second;
441 }
442
443-void TribeDescr::resize_ware_orders(size_t maxLength) {
444- bool need_resize = false;
445-
446- // Check if we actually need to resize.
447- for (WaresOrder::iterator it = wares_order_.begin(); it != wares_order_.end(); ++it) {
448- if (it->size() > maxLength) {
449- need_resize = true;
450- }
451- }
452-
453- // Build new smaller wares_order.
454- if (need_resize) {
455- WaresOrder new_wares_order;
456- for (WaresOrder::iterator it = wares_order_.begin(); it != wares_order_.end(); ++it) {
457- new_wares_order.push_back(std::vector<Widelands::DescriptionIndex>());
458- for (std::vector<Widelands::DescriptionIndex>::iterator it2 = it->begin();
459- it2 != it->end(); ++it2) {
460- if (new_wares_order.rbegin()->size() >= maxLength) {
461- new_wares_order.push_back(std::vector<Widelands::DescriptionIndex>());
462- }
463- new_wares_order.rbegin()->push_back(*it2);
464- wares_order_coords_[*it2].first = new_wares_order.size() - 1;
465- wares_order_coords_[*it2].second = new_wares_order.rbegin()->size() - 1;
466- }
467- }
468-
469- // Remove old array.
470- wares_order_.clear();
471- wares_order_ = new_wares_order;
472- }
473-}
474-
475 void TribeDescr::add_building(const std::string& buildingname) {
476 try {
477 DescriptionIndex index = tribes_.safe_building_index(buildingname);
478
479=== modified file 'src/logic/map_objects/tribes/tribe_descr.h'
480--- src/logic/map_objects/tribes/tribe_descr.h 2019-03-01 04:19:53 +0000
481+++ src/logic/map_objects/tribes/tribe_descr.h 2019-05-06 13:51:46 +0000
482@@ -149,22 +149,13 @@
483 }
484
485 using WaresOrder = std::vector<std::vector<Widelands::DescriptionIndex>>;
486- using WaresOrderCoords = std::vector<std::pair<uint32_t, uint32_t>>;
487 const WaresOrder& wares_order() const {
488 return wares_order_;
489 }
490- const WaresOrderCoords& wares_order_coords() const {
491- return wares_order_coords_;
492- }
493
494 const WaresOrder& workers_order() const {
495 return workers_order_;
496 }
497- const WaresOrderCoords& workers_order_coords() const {
498- return workers_order_coords_;
499- }
500-
501- void resize_ware_orders(size_t maxLength);
502
503 const std::vector<std::string>& get_ship_names() const {
504 return ship_names_;
505@@ -215,9 +206,7 @@
506 std::vector<DescriptionIndex> trainingsites_;
507 // Order and positioning of wares in the warehouse display
508 WaresOrder wares_order_;
509- WaresOrderCoords wares_order_coords_;
510 WaresOrder workers_order_;
511- WaresOrderCoords workers_order_coords_;
512
513 std::vector<Widelands::TribeBasicInfo::Initialization> initializations_;
514
515
516=== modified file 'src/logic/map_objects/tribes/tribes.cc'
517--- src/logic/map_objects/tribes/tribes.cc 2019-03-01 04:19:53 +0000
518+++ src/logic/map_objects/tribes/tribes.cc 2019-05-06 13:51:46 +0000
519@@ -340,14 +340,9 @@
520 // Calculate the trainingsites proportions.
521 postload_calculate_trainingsites_proportions();
522
523- // Resize the configuration of our wares if they won't fit in the current window (12 = info label
524- // size).
525- // Also, do some final checks on the gamedata
526- int number = (g_gr->get_yres() - 290) / (WARE_MENU_PIC_HEIGHT + WARE_MENU_PIC_PAD_Y + 12);
527+ // Some final checks on the gamedata
528 for (DescriptionIndex i = 0; i < tribes_->size(); ++i) {
529 TribeDescr* tribe_descr = tribes_->get_mutable(i);
530- tribe_descr->resize_ware_orders(number);
531-
532 // Verify that the preciousness has been set for all of the tribe's wares
533 for (const DescriptionIndex wi : tribe_descr->wares()) {
534 if (tribe_descr->get_ware_descr(wi)->preciousness(tribe_descr->name()) == kInvalidWare) {
535
536=== modified file 'src/logic/map_objects/tribes/ware_descr.h'
537--- src/logic/map_objects/tribes/ware_descr.h 2019-02-27 19:00:36 +0000
538+++ src/logic/map_objects/tribes/ware_descr.h 2019-05-06 13:51:46 +0000
539@@ -33,10 +33,8 @@
540 class Image;
541 class LuaTable;
542
543-#define WARE_MENU_PIC_WIDTH 24 //!< Default width for ware's menu icons
544-#define WARE_MENU_PIC_HEIGHT 24 //!< Default height for ware's menu icons
545-#define WARE_MENU_PIC_PAD_X 3 //!< Default padding between menu icons
546-#define WARE_MENU_PIC_PAD_Y 4 //!< Default padding between menu icons
547+constexpr int kWareMenuPicWidth = 24; //!< Default width for ware's menu icons
548+constexpr int kWareMenuPicHeight = 24; //!< Default height for ware's menu icons
549
550 namespace Widelands {
551
552
553=== modified file 'src/logic/playercommand.h'
554--- src/logic/playercommand.h 2019-02-23 11:00:49 +0000
555+++ src/logic/playercommand.h 2019-05-06 13:51:46 +0000
556@@ -581,6 +581,7 @@
557 uint32_t permanent_;
558 };
559
560+// TODO(Nordfriese): CmdResetWareTargetQuantity can be removed when we next break savegame compatibility
561 struct CmdResetWareTargetQuantity : public CmdChangeTargetQuantity {
562 CmdResetWareTargetQuantity() : CmdChangeTargetQuantity() {
563 }
564@@ -629,6 +630,7 @@
565 uint32_t permanent_;
566 };
567
568+// TODO(Nordfriese): CmdResetWorkerTargetQuantity can be removed when we next break savegame compatibility
569 struct CmdResetWorkerTargetQuantity : public CmdChangeTargetQuantity {
570 CmdResetWorkerTargetQuantity() : CmdChangeTargetQuantity() {
571 }
572
573=== modified file 'src/wui/CMakeLists.txt'
574--- src/wui/CMakeLists.txt 2019-05-04 15:37:33 +0000
575+++ src/wui/CMakeLists.txt 2019-05-06 13:51:46 +0000
576@@ -44,8 +44,10 @@
577 graphic
578 logic
579 logic_commands
580+ logic_filesystem_constants
581 logic_map_objects
582 notifications
583+ profile
584 ui_basic
585 wui_waresdisplay
586 )
587
588=== modified file 'src/wui/economy_options_window.cc'
589--- src/wui/economy_options_window.cc 2019-02-23 11:00:49 +0000
590+++ src/wui/economy_options_window.cc 2019-05-06 13:51:46 +0000
591@@ -19,36 +19,98 @@
592
593 #include "wui/economy_options_window.h"
594
595+#include <memory>
596+
597 #include <boost/lexical_cast.hpp>
598
599 #include "graphic/graphic.h"
600 #include "logic/editor_game_base.h"
601+#include "logic/filesystem_constants.h"
602 #include "logic/map_objects/tribes/ware_descr.h"
603 #include "logic/map_objects/tribes/worker_descr.h"
604 #include "logic/player.h"
605 #include "logic/playercommand.h"
606+#include "profile/profile.h"
607 #include "ui_basic/button.h"
608+#include "ui_basic/editbox.h"
609+#include "ui_basic/messagebox.h"
610+#include "ui_basic/table.h"
611
612 static const char pic_tab_wares[] = "images/wui/buildings/menu_tab_wares.png";
613 static const char pic_tab_workers[] = "images/wui/buildings/menu_tab_workers.png";
614
615+constexpr int kDesiredWidth = 216;
616+
617+static inline int32_t calc_hgap(int32_t columns, int32_t total_w) {
618+ return (total_w - columns * kWareMenuPicWidth) / (columns - 1);
619+}
620+
621 EconomyOptionsWindow::EconomyOptionsWindow(UI::Panel* parent,
622 Widelands::Economy* economy,
623 bool can_act)
624 : UI::Window(parent, "economy_options", 0, 0, 0, 0, _("Economy options")),
625+ main_box_(this, 0, 0, UI::Box::Vertical),
626 serial_(economy->serial()),
627 player_(&economy->owner()),
628 tabpanel_(this, UI::TabPanelStyle::kWuiDark),
629- ware_panel_(new EconomyOptionsPanel(&tabpanel_, serial_, player_, can_act, Widelands::wwWARE)),
630+ ware_panel_(new EconomyOptionsPanel(&tabpanel_, this, serial_, player_, can_act, Widelands::wwWARE, kDesiredWidth)),
631 worker_panel_(
632- new EconomyOptionsPanel(&tabpanel_, serial_, player_, can_act, Widelands::wwWORKER)) {
633- set_center_panel(&tabpanel_);
634+ new EconomyOptionsPanel(&tabpanel_, this, serial_, player_, can_act, Widelands::wwWORKER, kDesiredWidth)),
635+ dropdown_box_(this, 0, 0, UI::Box::Horizontal),
636+ dropdown_(&dropdown_box_, 0, 0, 174, 200, 34, "", UI::DropdownType::kTextual, UI::PanelStyle::kWui) {
637+ set_center_panel(&main_box_);
638
639 tabpanel_.add("wares", g_gr->images().get(pic_tab_wares), ware_panel_, _("Wares"));
640 tabpanel_.add("workers", g_gr->images().get(pic_tab_workers), worker_panel_, _("Workers"));
641+
642+ UI::Box* buttons = new UI::Box(this, 0, 0, UI::Box::Horizontal);
643+ UI::Button* b = new UI::Button(buttons, "decrease_target_fast", 0, 0, 44, 28, UI::ButtonStyle::kWuiSecondary,
644+ g_gr->images().get("images/ui_basic/scrollbar_down_fast.png"), _("Decrease target by 10"));
645+ b->sigclicked.connect([this] { change_target(-10); });
646+ buttons->add(b);
647+ b->set_repeating(true);
648+ buttons->add_space(8);
649+ b = new UI::Button(buttons, "decrease_target", 0, 0, 44, 28, UI::ButtonStyle::kWuiSecondary,
650+ g_gr->images().get("images/ui_basic/scrollbar_down.png"), _("Decrease target"));
651+ b->sigclicked.connect([this] { change_target(-1); });
652+ buttons->add(b);
653+ b->set_repeating(true);
654+ buttons->add_space(24);
655+
656+ b = new UI::Button(buttons, "increase_target", 0, 0, 44, 28, UI::ButtonStyle::kWuiSecondary,
657+ g_gr->images().get("images/ui_basic/scrollbar_up.png"), _("Increase target"));
658+ b->sigclicked.connect([this] { change_target(1); });
659+ buttons->add(b);
660+ b->set_repeating(true);
661+ buttons->add_space(8);
662+ b = new UI::Button(buttons, "increase_target_fast", 0, 0, 44, 28, UI::ButtonStyle::kWuiSecondary,
663+ g_gr->images().get("images/ui_basic/scrollbar_up_fast.png"), _("Increase target by 10"));
664+ b->sigclicked.connect([this] { change_target(10); });
665+ buttons->add(b);
666+ b->set_repeating(true);
667+
668+ dropdown_.set_tooltip(_("Profile to apply to the selected items"));
669+ dropdown_box_.set_size(40, 20); // Prevent assert failures
670+ dropdown_box_.add(&dropdown_, UI::Box::Resizing::kFullSize);
671+ dropdown_.selected.connect([this] { reset_target(); });
672+
673+ b = new UI::Button(&dropdown_box_, "save_targets", 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu,
674+ g_gr->images().get("images/wui/menus/menu_save_game.png"), _("Save target settings"));
675+ b->sigclicked.connect([this] { create_target(); });
676+ dropdown_box_.add_space(8);
677+ dropdown_box_.add(b);
678+
679+ main_box_.add(&tabpanel_, UI::Box::Resizing::kAlign, UI::Align::kCenter);
680+ main_box_.add_space(8);
681+ main_box_.add(buttons, UI::Box::Resizing::kAlign, UI::Align::kCenter);
682+ main_box_.add_space(8);
683+ main_box_.add(&dropdown_box_, UI::Box::Resizing::kAlign, UI::Align::kCenter);
684+
685 economy->set_has_window(true);
686 economynotes_subscriber_ = Notifications::subscribe<Widelands::NoteEconomy>(
687 [this](const Widelands::NoteEconomy& note) { on_economy_note(note); });
688+
689+ read_targets();
690 }
691
692 EconomyOptionsWindow::~EconomyOptionsWindow() {
693@@ -81,6 +143,20 @@
694 }
695 }
696
697+void EconomyOptionsWindow::layout() {
698+ int w, h;
699+ tabpanel_.get_desired_size(&w, &h);
700+ main_box_.set_desired_size(w, h + 78);
701+ update_desired_size();
702+ UI::Window::layout();
703+}
704+
705+void EconomyOptionsWindow::EconomyOptionsPanel::update_desired_size() {
706+ display_.set_hgap(std::max(3, calc_hgap(display_.get_extent().w, kDesiredWidth)));
707+ Box::update_desired_size();
708+ get_parent()->layout();
709+}
710+
711 EconomyOptionsWindow::TargetWaresDisplay::TargetWaresDisplay(UI::Panel* const parent,
712 int32_t const x,
713 int32_t const y,
714@@ -129,42 +205,26 @@
715 * Wraps the wares/workers display together with some buttons
716 */
717 EconomyOptionsWindow::EconomyOptionsPanel::EconomyOptionsPanel(UI::Panel* parent,
718+ EconomyOptionsWindow* eco_window,
719 Widelands::Serial serial,
720 Widelands::Player* player,
721 bool can_act,
722- Widelands::WareWorker type)
723+ Widelands::WareWorker type,
724+ int32_t min_w)
725 : UI::Box(parent, 0, 0, UI::Box::Vertical),
726 serial_(serial),
727 player_(player),
728 type_(type),
729 can_act_(can_act),
730- display_(this, 0, 0, serial_, player_, type_, can_act_) {
731+ display_(this, 0, 0, serial_, player_, type_, can_act_),
732+ economy_options_window_(eco_window) {
733 add(&display_, UI::Box::Resizing::kFullSize);
734
735+ display_.set_hgap(std::max(3, calc_hgap(display_.get_extent().w, min_w)));
736+
737 if (!can_act_) {
738 return;
739 }
740- UI::Box* buttons = new UI::Box(this, 0, 0, UI::Box::Horizontal);
741- add(buttons);
742-
743- UI::Button* b = new UI::Button(buttons, "decrease_target", 0, 0, 34, 34,
744- UI::ButtonStyle::kWuiMenu, "-", _("Decrease target"));
745- b->sigclicked.connect(boost::bind(&EconomyOptionsPanel::change_target, this, -1));
746- buttons->add(b);
747- b->set_repeating(true);
748- buttons->add_space(8);
749-
750- b = new UI::Button(buttons, "increase_target", 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu, "+",
751- _("Increase target"));
752- b->sigclicked.connect(boost::bind(&EconomyOptionsPanel::change_target, this, 1));
753- buttons->add(b);
754- b->set_repeating(true);
755- buttons->add_space(8);
756-
757- b = new UI::Button(
758- buttons, "reset_target", 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu, "R", _("Reset to default"));
759- b->sigclicked.connect(boost::bind(&EconomyOptionsPanel::reset_target, this));
760- buttons->add(b);
761 }
762
763 void EconomyOptionsWindow::EconomyOptionsPanel::set_economy(Widelands::Serial serial) {
764@@ -172,7 +232,26 @@
765 display_.set_economy(serial);
766 }
767
768-void EconomyOptionsWindow::EconomyOptionsPanel::change_target(int amount) {
769+void EconomyOptionsWindow::change_target(int amount) {
770+ if (tabpanel_.active() == 0) {
771+ ware_panel_->change_target(amount);
772+ } else {
773+ worker_panel_->change_target(amount);
774+ }
775+}
776+
777+void EconomyOptionsWindow::reset_target() {
778+ if (tabpanel_.active() == 0) {
779+ ware_panel_->reset_target();
780+ } else {
781+ worker_panel_->reset_target();
782+ }
783+}
784+
785+void EconomyOptionsWindow::EconomyOptionsPanel::change_target(int delta) {
786+ if (delta == 0) {
787+ return;
788+ }
789 Widelands::Economy* economy = player_->get_economy(serial_);
790 if (economy == nullptr) {
791 die();
792@@ -186,35 +265,286 @@
793 const Widelands::Economy::TargetQuantity& tq = is_wares ?
794 economy->ware_target_quantity(index) :
795 economy->worker_target_quantity(index);
796- // Don't allow negative new amount.
797- if (amount >= 0 || -amount <= static_cast<int>(tq.permanent)) {
798- if (is_wares) {
799- game.send_player_command(*new Widelands::CmdSetWareTargetQuantity(
800- game.get_gametime(), player_->player_number(), serial_, index,
801- tq.permanent + amount));
802+ // Don't allow negative new amount
803+ const int old_amount = static_cast<int>(tq.permanent);
804+ const int new_amount = std::max(0, old_amount + delta);
805+ if (new_amount == old_amount) {
806+ continue;
807+ }
808+ if (is_wares) {
809+ game.send_player_command(*new Widelands::CmdSetWareTargetQuantity(
810+ game.get_gametime(), player_->player_number(), serial_, index, new_amount));
811+ } else {
812+ game.send_player_command(*new Widelands::CmdSetWorkerTargetQuantity(
813+ game.get_gametime(), player_->player_number(), serial_, index, new_amount));
814+ }
815+ }
816+ }
817+}
818+
819+void EconomyOptionsWindow::EconomyOptionsPanel::reset_target() {
820+ Widelands::Game& game = dynamic_cast<Widelands::Game&>(player_->egbase());
821+ const bool is_wares = type_ == Widelands::wwWARE;
822+ const auto& items = is_wares ? player_->tribe().wares() : player_->tribe().workers();
823+ const PredefinedTargets settings = economy_options_window_->get_selected_target();
824+ for (const Widelands::DescriptionIndex& index : items) {
825+ if (display_.ware_selected(index)) {
826+ if (is_wares) {
827+ game.send_player_command(*new Widelands::CmdSetWareTargetQuantity(
828+ game.get_gametime(), player_->player_number(), serial_, index, settings.wares.at(index)));
829+ } else {
830+ game.send_player_command(*new Widelands::CmdSetWorkerTargetQuantity(
831+ game.get_gametime(), player_->player_number(), serial_, index, settings.workers.at(index)));
832+ }
833+ }
834+ }
835+}
836+
837+void EconomyOptionsWindow::update_profiles(const std::string& select) {
838+ dropdown_.clear();
839+ for (const auto& pair : predefined_targets_) {
840+ dropdown_.add(_(pair.first), pair.first, nullptr, pair.first == select);
841+ }
842+}
843+
844+struct SaveProfileWindow : public UI::Window {
845+ void update_save_enabled() {
846+ const std::string& text = profile_name_.text();
847+ if (text.empty() || text == kDefaultEconomyProfile) {
848+ save_.set_enabled(false);
849+ save_.set_tooltip(text.empty() ? _("The profile name cannot be empty") :
850+ _("The default profile cannot be overwritten"));
851+ } else {
852+ save_.set_enabled(true);
853+ save_.set_tooltip(_("Save the profile under this name"));
854+ }
855+ }
856+
857+ void table_selection_changed() {
858+ if (!table_.has_selection()) {
859+ delete_.set_enabled(false);
860+ delete_.set_tooltip("");
861+ return;
862+ }
863+ const std::string& sel = table_[table_.selection_index()];
864+ if (sel == kDefaultEconomyProfile) {
865+ delete_.set_tooltip(_("The default profile cannot be deleted"));
866+ delete_.set_enabled(false);
867+ } else {
868+ delete_.set_tooltip(_("Delete the selected profiles"));
869+ delete_.set_enabled(true);
870+ }
871+ profile_name_.set_text(sel);
872+ update_save_enabled();
873+ }
874+
875+ void close(bool ok) {
876+ end_modal(ok ? UI::Panel::Returncodes::kOk : UI::Panel::Returncodes::kBack);
877+ die();
878+ }
879+
880+ void update_table() {
881+ table_.clear();
882+ for (const auto& pair : economy_options_->get_predefined_targets()) {
883+ table_.add(pair.first).set_string(0, _(pair.first));
884+ }
885+ layout();
886+ }
887+
888+ void save() {
889+ const std::string name = profile_name_.text();
890+ assert(!name.empty());
891+ assert(name != kDefaultEconomyProfile);
892+ for (const auto& pair : economy_options_->get_predefined_targets()) {
893+ if (pair.first == name) {
894+ UI::WLMessageBox m(this, _("Overwrite?"),
895+ _("A profile with this name already exists.\nDo you wish to replace it?"),
896+ UI::WLMessageBox::MBoxType::kOkCancel);
897+ if (m.run<UI::Panel::Returncodes>() != UI::Panel::Returncodes::kOk) {
898+ return;
899+ }
900+ break;
901+ }
902+ }
903+ economy_options_->do_create_target(name);
904+ close(true);
905+ }
906+
907+ void delete_selected() {
908+ assert(table_.has_selection());
909+ auto& map = economy_options_->get_predefined_targets();
910+ const std::string& name = table_[table_.selection_index()];
911+ assert(name != kDefaultEconomyProfile);
912+ for (auto it = map.begin(); it != map.end(); ++it) {
913+ if (it->first == name) {
914+ map.erase(it);
915+ break;
916+ }
917+ }
918+ economy_options_->save_targets();
919+ update_table();
920+ }
921+
922+ explicit SaveProfileWindow(UI::Panel* parent, EconomyOptionsWindow* eco)
923+ : UI::Window(parent, "save_economy_options_profile", 0, 0, 0, 0, _("Save Profile")),
924+ economy_options_(eco),
925+ main_box_(this, 0, 0, UI::Box::Vertical),
926+ table_box_(&main_box_, 0, 0, UI::Box::Vertical),
927+ table_(&table_box_, 0, 0, 460, 120, UI::PanelStyle::kWui),
928+ buttons_box_(&main_box_, 0, 0, UI::Box::Horizontal),
929+ profile_name_(&buttons_box_, 0, 0, 240, 0, 0, UI::PanelStyle::kWui),
930+ save_(&buttons_box_, "save", 0, 0, 80, 34, UI::ButtonStyle::kWuiPrimary, _("Save")),
931+ cancel_(&buttons_box_, "cancel", 0, 0, 80, 34, UI::ButtonStyle::kWuiSecondary, _("Cancel")),
932+ delete_(&buttons_box_, "delete", 0, 0, 80, 34, UI::ButtonStyle::kWuiSecondary, _("Delete")) {
933+ table_.add_column(200, _("Existing Profiles"));
934+ update_table();
935+
936+ table_.selected.connect([this](uint32_t) { table_selection_changed(); });
937+ profile_name_.changed.connect([this] { update_save_enabled(); });
938+ profile_name_.ok.connect([this] { save(); });
939+ profile_name_.cancel.connect([this] { close(false); });
940+ save_.sigclicked.connect([this] { save(); });
941+ cancel_.sigclicked.connect([this] { close(false); });
942+ delete_.sigclicked.connect([this] { delete_selected(); });
943+
944+ table_box_.add(&table_, UI::Box::Resizing::kFullSize);
945+ buttons_box_.add(&profile_name_, UI::Box::Resizing::kFullSize);
946+ buttons_box_.add(&save_);
947+ buttons_box_.add(&cancel_);
948+ buttons_box_.add(&delete_);
949+ main_box_.add(&table_box_, UI::Box::Resizing::kFullSize);
950+ main_box_.add(&buttons_box_, UI::Box::Resizing::kFullSize);
951+ set_center_panel(&main_box_);
952+
953+ table_selection_changed();
954+ update_save_enabled();
955+ }
956+ ~SaveProfileWindow() {
957+ }
958+
959+private:
960+ EconomyOptionsWindow* economy_options_;
961+ UI::Box main_box_;
962+ UI::Box table_box_;
963+ UI::Table<const std::string&> table_;
964+ UI::Box buttons_box_;
965+ UI::EditBox profile_name_;
966+ UI::Button save_;
967+ UI::Button cancel_;
968+ UI::Button delete_;
969+};
970+
971+void EconomyOptionsWindow::create_target() {
972+ std::unique_ptr<SaveProfileWindow> s (new SaveProfileWindow(get_parent(), this));
973+ s->run<UI::Panel::Returncodes>();
974+}
975+
976+void EconomyOptionsWindow::do_create_target(const std::string& name) {
977+ assert(!name.empty());
978+ assert(name != kDefaultEconomyProfile);
979+ const Widelands::Tribes& tribes = player_->egbase().tribes();
980+ const Widelands::TribeDescr& tribe = player_->tribe();
981+ Widelands::Economy* economy = player_->get_economy(serial_);
982+ PredefinedTargets t;
983+ for (Widelands::DescriptionIndex di : tribe.wares()) {
984+ if (tribes.get_ware_descr(di)->has_demand_check(tribe.name())) {
985+ t.wares[di] = economy->ware_target_quantity(di).permanent;
986+ }
987+ }
988+ for (Widelands::DescriptionIndex di : tribe.workers()) {
989+ if (tribes.get_worker_descr(di)->has_demand_check()) {
990+ t.workers[di] = economy->worker_target_quantity(di).permanent;
991+ }
992+ }
993+ predefined_targets_[name] = t;
994+
995+ save_targets();
996+ update_profiles(name);
997+}
998+
999+void EconomyOptionsWindow::save_targets() {
1000+ const Widelands::Tribes& tribes = player_->egbase().tribes();
1001+ Profile profile;
1002+
1003+ std::map<std::string, uint32_t> serials;
1004+ for (const auto& pair : predefined_targets_) {
1005+ if (pair.first != kDefaultEconomyProfile) {
1006+ serials.emplace(pair.first, serials.size());
1007+ }
1008+ }
1009+ Section& global_section = profile.create_section(kDefaultEconomyProfile.c_str());
1010+ for (const auto& pair : serials) {
1011+ global_section.set_string(std::to_string(pair.second).c_str(), pair.first);
1012+ }
1013+
1014+ for (const auto& pair : predefined_targets_) {
1015+ if (pair.first == kDefaultEconomyProfile) {
1016+ continue;
1017+ }
1018+ Section& section = profile.create_section(std::to_string(serials.at(pair.first)).c_str());
1019+ for (const auto& setting : pair.second.wares) {
1020+ section.set_natural(tribes.get_ware_descr(setting.first)->name().c_str(), setting.second);
1021+ }
1022+ for (const auto& setting : pair.second.workers) {
1023+ section.set_natural(tribes.get_worker_descr(setting.first)->name().c_str(), setting.second);
1024+ }
1025+ }
1026+
1027+ g_fs->ensure_directory_exists(kEconomyProfilesDir);
1028+ std::string complete_filename = kEconomyProfilesDir + g_fs->file_separator() + player_->tribe().name();
1029+ profile.write(complete_filename.c_str(), false);
1030+}
1031+
1032+void EconomyOptionsWindow::read_targets(const std::string& select) {
1033+ predefined_targets_.clear();
1034+ const Widelands::Tribes& tribes = player_->egbase().tribes();
1035+ const Widelands::TribeDescr& tribe = player_->tribe();
1036+
1037+ {
1038+ PredefinedTargets t;
1039+ for (Widelands::DescriptionIndex di : tribe.wares()) {
1040+ const Widelands::WareDescr* descr = tribes.get_ware_descr(di);
1041+ if (descr->has_demand_check(tribe.name())) {
1042+ t.wares.emplace(di, descr->default_target_quantity(tribe.name()));
1043+ }
1044+ }
1045+ for (Widelands::DescriptionIndex di : tribe.workers()) {
1046+ const Widelands::WorkerDescr* descr = tribes.get_worker_descr(di);
1047+ if (descr->has_demand_check()) {
1048+ t.workers.emplace(di, descr->default_target_quantity());
1049+ }
1050+ }
1051+ predefined_targets_.emplace(kDefaultEconomyProfile, t);
1052+ }
1053+
1054+ std::string complete_filename = kEconomyProfilesDir + g_fs->file_separator() + player_->tribe().name();
1055+ Profile profile;
1056+ profile.read(complete_filename.c_str());
1057+
1058+ Section* global_section = profile.get_section(kDefaultEconomyProfile);
1059+ if (global_section) {
1060+ std::map<std::string, std::string> serials;
1061+ while (Section::Value* v = global_section->get_next_val()) {
1062+ serials.emplace(std::string(v->get_name()), v->get_string());
1063+ }
1064+
1065+ for (const auto& pair : serials) {
1066+ Section* section = profile.get_section(pair.first);
1067+ PredefinedTargets t;
1068+ while (Section::Value* v = section->get_next_val()) {
1069+ const std::string name = std::string(v->get_name());
1070+ Widelands::DescriptionIndex di = tribes.ware_index(name);
1071+ if (di == Widelands::INVALID_INDEX) {
1072+ di = tribes.worker_index(name);
1073+ assert(di != Widelands::INVALID_INDEX);
1074+ t.workers.emplace(di, v->get_natural());
1075 } else {
1076- game.send_player_command(*new Widelands::CmdSetWorkerTargetQuantity(
1077- game.get_gametime(), player_->player_number(), serial_, index,
1078- tq.permanent + amount));
1079+ t.wares.emplace(di, v->get_natural());
1080 }
1081 }
1082+ predefined_targets_.emplace(pair.second, t);
1083 }
1084 }
1085-}
1086
1087-void EconomyOptionsWindow::EconomyOptionsPanel::reset_target() {
1088- Widelands::Game& game = dynamic_cast<Widelands::Game&>(player_->egbase());
1089- const bool is_wares = type_ == Widelands::wwWARE;
1090- const auto& items = is_wares ? player_->tribe().wares() : player_->tribe().workers();
1091- for (const Widelands::DescriptionIndex& index : items) {
1092- if (display_.ware_selected(index)) {
1093- if (is_wares) {
1094- game.send_player_command(*new Widelands::CmdResetWareTargetQuantity(
1095- game.get_gametime(), player_->player_number(), serial_, index));
1096- } else {
1097- game.send_player_command(*new Widelands::CmdResetWorkerTargetQuantity(
1098- game.get_gametime(), player_->player_number(), serial_, index));
1099- }
1100- }
1101- }
1102+ update_profiles(select);
1103 }
1104
1105=== modified file 'src/wui/economy_options_window.h'
1106--- src/wui/economy_options_window.h 2019-02-23 11:00:49 +0000
1107+++ src/wui/economy_options_window.h 2019-05-06 13:51:46 +0000
1108@@ -20,20 +20,48 @@
1109 #ifndef WL_WUI_ECONOMY_OPTIONS_WINDOW_H
1110 #define WL_WUI_ECONOMY_OPTIONS_WINDOW_H
1111
1112+#include <map>
1113 #include <memory>
1114+#include <string>
1115
1116 #include "economy/economy.h"
1117 #include "logic/map_objects/tribes/tribe_descr.h"
1118 #include "notifications/notifications.h"
1119 #include "ui_basic/box.h"
1120+#include "ui_basic/dropdown.h"
1121 #include "ui_basic/tabpanel.h"
1122 #include "ui_basic/window.h"
1123 #include "wui/waresdisplay.h"
1124
1125+const std::string kDefaultEconomyProfile = "Default";
1126+
1127 struct EconomyOptionsWindow : public UI::Window {
1128 EconomyOptionsWindow(UI::Panel* parent, Widelands::Economy* economy, bool can_act);
1129 ~EconomyOptionsWindow();
1130
1131+ struct PredefinedTargets {
1132+ using Targets = std::map<Widelands::DescriptionIndex, uint32_t>;
1133+ Targets wares;
1134+ Targets workers;
1135+ };
1136+
1137+ void create_target();
1138+ void do_create_target(const std::string&);
1139+ void save_targets();
1140+ void read_targets(const std::string& = kDefaultEconomyProfile);
1141+ void update_profiles(const std::string&);
1142+ std::map<std::string, PredefinedTargets>& get_predefined_targets() {
1143+ return predefined_targets_;
1144+ }
1145+ const PredefinedTargets& get_selected_target() const {
1146+ return predefined_targets_.at(dropdown_.get_selected());
1147+ }
1148+
1149+ void change_target(int amount);
1150+ void reset_target();
1151+
1152+ void layout() override;
1153+
1154 private:
1155 struct TargetWaresDisplay : public AbstractWaresDisplay {
1156 TargetWaresDisplay(UI::Panel* const parent,
1157@@ -59,14 +87,17 @@
1158 */
1159 struct EconomyOptionsPanel : UI::Box {
1160 EconomyOptionsPanel(UI::Panel* parent,
1161+ EconomyOptionsWindow* eco_window,
1162 Widelands::Serial serial,
1163 Widelands::Player* player,
1164 bool can_act,
1165- Widelands::WareWorker type);
1166+ Widelands::WareWorker type,
1167+ int32_t min_w);
1168
1169 void set_economy(Widelands::Serial serial);
1170 void change_target(int amount);
1171 void reset_target();
1172+ void update_desired_size() override;
1173
1174 private:
1175 Widelands::Serial serial_;
1176@@ -74,17 +105,23 @@
1177 Widelands::WareWorker type_;
1178 bool can_act_;
1179 TargetWaresDisplay display_;
1180+ EconomyOptionsWindow* economy_options_window_;
1181 };
1182
1183 /// Actions performed when a NoteEconomyWindow is received.
1184 void on_economy_note(const Widelands::NoteEconomy& note);
1185
1186+ UI::Box main_box_;
1187 Widelands::Serial serial_;
1188 Widelands::Player* player_;
1189 UI::TabPanel tabpanel_;
1190 EconomyOptionsPanel* ware_panel_;
1191 EconomyOptionsPanel* worker_panel_;
1192 std::unique_ptr<Notifications::Subscriber<Widelands::NoteEconomy>> economynotes_subscriber_;
1193+
1194+ std::map<std::string, PredefinedTargets> predefined_targets_;
1195+ UI::Box dropdown_box_;
1196+ UI::Dropdown<std::string> dropdown_;
1197 };
1198
1199 #endif // end of include guard: WL_WUI_ECONOMY_OPTIONS_WINDOW_H
1200
1201=== modified file 'src/wui/inputqueuedisplay.cc'
1202--- src/wui/inputqueuedisplay.cc 2019-04-25 06:40:24 +0000
1203+++ src/wui/inputqueuedisplay.cc 2019-05-06 13:51:46 +0000
1204@@ -71,7 +71,7 @@
1205
1206 uint32_t priority_button_height = show_only ? 0 : 3 * PriorityButtonSize;
1207 uint32_t image_height =
1208- show_only ? WARE_MENU_PIC_HEIGHT : std::max<int32_t>(WARE_MENU_PIC_HEIGHT, ph);
1209+ show_only ? kWareMenuPicHeight : std::max<int32_t>(kWareMenuPicHeight, ph);
1210
1211 total_height_ = std::max(priority_button_height, image_height) + 2 * Border;
1212
1213@@ -91,7 +91,7 @@
1214 */
1215 void InputQueueDisplay::max_size_changed() {
1216 uint32_t pbs = show_only_ ? 0 : PriorityButtonSize;
1217- uint32_t ctrl_b_size = show_only_ ? 0 : 2 * WARE_MENU_PIC_WIDTH;
1218+ uint32_t ctrl_b_size = show_only_ ? 0 : 2 * kWareMenuPicWidth;
1219
1220 cache_size_ = queue_.get_max_size();
1221
1222@@ -140,7 +140,7 @@
1223
1224 Vector2i point = Vector2i::zero();
1225 point.x = Border + (show_only_ ? 0 : CellWidth + CellSpacing);
1226- point.y = Border + (total_height_ - 2 * Border - WARE_MENU_PIC_HEIGHT) / 2;
1227+ point.y = Border + (total_height_ - 2 * Border - kWareMenuPicHeight) / 2;
1228
1229 for (; nr_inputs_to_draw; --nr_inputs_to_draw, point.x += CellWidth + CellSpacing) {
1230 dst.blitrect(Vector2i(point.x, point.y), icon_, Recti(0, 0, icon_->width(), icon_->height()),
1231@@ -240,12 +240,12 @@
1232 return;
1233
1234 uint32_t x = Border;
1235- uint32_t y = Border + (total_height_ - 2 * Border - WARE_MENU_PIC_WIDTH) / 2;
1236+ uint32_t y = Border + (total_height_ - 2 * Border - kWareMenuPicWidth) / 2;
1237
1238 boost::format tooltip_format("%s<br><p><font size=%d bold=0>%s<br>%s</font></p>");
1239
1240 decrease_max_fill_ = new UI::Button(
1241- this, "decrease_max_fill", x, y, WARE_MENU_PIC_WIDTH, WARE_MENU_PIC_HEIGHT,
1242+ this, "decrease_max_fill", x, y, kWareMenuPicWidth, kWareMenuPicHeight,
1243 UI::ButtonStyle::kWuiMenu, g_gr->images().get("images/ui_basic/scrollbar_left.png"),
1244 (tooltip_format
1245 /** TRANSLATORS: Button tooltip in in a building's wares input queue */
1246@@ -262,7 +262,7 @@
1247 x = Border + (cache_size_ + 1) * (CellWidth + CellSpacing);
1248
1249 increase_max_fill_ = new UI::Button(
1250- this, "increase_max_fill", x, y, WARE_MENU_PIC_WIDTH, WARE_MENU_PIC_HEIGHT,
1251+ this, "increase_max_fill", x, y, kWareMenuPicWidth, kWareMenuPicHeight,
1252 UI::ButtonStyle::kWuiMenu, g_gr->images().get("images/ui_basic/scrollbar_right.png"),
1253 (tooltip_format
1254 /** TRANSLATORS: Button tooltip in a building's wares input queue */
1255
1256=== modified file 'src/wui/inputqueuedisplay.h'
1257--- src/wui/inputqueuedisplay.h 2019-04-23 14:53:35 +0000
1258+++ src/wui/inputqueuedisplay.h 2019-05-06 13:51:46 +0000
1259@@ -49,7 +49,7 @@
1260 */
1261 class InputQueueDisplay : public UI::Panel {
1262 public:
1263- enum { CellWidth = WARE_MENU_PIC_WIDTH, CellSpacing = 2, Border = 4, PriorityButtonSize = 10 };
1264+ enum { CellWidth = kWareMenuPicWidth, CellSpacing = 2, Border = 4, PriorityButtonSize = 10 };
1265
1266 InputQueueDisplay(UI::Panel* parent,
1267 int32_t x,
1268
1269=== modified file 'src/wui/waresdisplay.cc'
1270--- src/wui/waresdisplay.cc 2019-02-23 11:00:49 +0000
1271+++ src/wui/waresdisplay.cc 2019-05-06 13:51:46 +0000
1272@@ -35,8 +35,9 @@
1273 #include "logic/map_objects/tribes/ware_descr.h"
1274 #include "logic/map_objects/tribes/worker.h"
1275 #include "logic/player.h"
1276+#include "ui_basic/window.h"
1277
1278-const int WARE_MENU_INFO_SIZE = 12;
1279+constexpr int kWareMenuInfoSize = 12;
1280
1281 AbstractWaresDisplay::AbstractWaresDisplay(
1282 UI::Panel* const parent,
1283@@ -46,7 +47,9 @@
1284 Widelands::WareWorker type,
1285 bool selectable,
1286 boost::function<void(Widelands::DescriptionIndex, bool)> callback_function,
1287- bool horizontal)
1288+ bool horizontal,
1289+ int32_t hgap,
1290+ int32_t vgap)
1291 : // Size is set when add_warelist is called, as it depends on the type_.
1292 UI::Panel(parent, x, y, 0, 0),
1293 tribe_(tribe),
1294@@ -57,6 +60,8 @@
1295
1296 selectable_(selectable),
1297 horizontal_(horizontal),
1298+ hgap_(hgap),
1299+ vgap_(vgap),
1300 selection_anchor_(Widelands::INVALID_INDEX),
1301 callback_function_(callback_function) {
1302 for (const Widelands::DescriptionIndex& index : indices_) {
1303@@ -67,22 +72,65 @@
1304
1305 curware_.set_text(_("Stock"));
1306
1307- // Find out geometry from icons_order
1308- unsigned int columns = icons_order().size();
1309- unsigned int rows = 0;
1310- for (unsigned int i = 0; i < icons_order().size(); i++)
1311- if (icons_order()[i].size() > rows)
1312- rows = icons_order()[i].size();
1313+ graphic_resolution_changed_subscriber_ = Notifications::subscribe<GraphicResolutionChanged>(
1314+ [this](const GraphicResolutionChanged&) {
1315+ recalc_desired_size(true);
1316+ });
1317+
1318+ recalc_desired_size(false);
1319+}
1320+
1321+Widelands::Extent AbstractWaresDisplay::get_extent() const {
1322+ int16_t columns = 0;
1323+ int16_t rows = 0;
1324+ for (const auto& pair : icons_order_coords()) {
1325+ columns = std::max(columns, pair.second.x);
1326+ rows = std::max(rows, pair.second.y);
1327+ }
1328+ // We cound from 0 up
1329+ ++columns;
1330+ ++rows;
1331+
1332 if (horizontal_) {
1333- unsigned int s = columns;
1334+ const int16_t s = columns;
1335 columns = rows;
1336 rows = s;
1337 }
1338+ return Widelands::Extent(columns, rows);
1339+}
1340+
1341+void AbstractWaresDisplay::set_hgap(int32_t gap) {
1342+ hgap_ = gap;
1343+ recalc_desired_size(true);
1344+}
1345+
1346+void AbstractWaresDisplay::set_vgap(int32_t gap) {
1347+ vgap_ = gap;
1348+ recalc_desired_size(true);
1349+}
1350+
1351+void AbstractWaresDisplay::recalc_desired_size(bool relayout) {
1352+ relayout_icons_order_coords();
1353+
1354+ // Find out geometry from icons_order
1355+ const Widelands::Extent size = get_extent();
1356
1357 // 25 is height of curware_ text
1358 set_desired_size(
1359- columns * (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X) + 1,
1360- rows * (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + WARE_MENU_PIC_PAD_Y) + 1 + 25);
1361+ size.w * (kWareMenuPicWidth + hgap_) + 1,
1362+ size.h * (kWareMenuPicHeight + kWareMenuInfoSize + vgap_) + 1 + 25);
1363+
1364+ if (relayout) {
1365+ // Since we are usually stacked deep within other panels, we need to tell our highest parent window to relayout
1366+ UI::Panel* p = this;
1367+ while (p->get_parent()) {
1368+ p = p->get_parent();
1369+ if (dynamic_cast<UI::Window*>(p)) {
1370+ p->layout();
1371+ return;
1372+ }
1373+ }
1374+ }
1375 }
1376
1377 bool AbstractWaresDisplay::handle_mousemove(uint8_t state, int32_t x, int32_t y, int32_t, int32_t) {
1378@@ -162,21 +210,33 @@
1379 * DescriptionIndex::null() if the given point is outside the range.
1380 */
1381 Widelands::DescriptionIndex AbstractWaresDisplay::ware_at_point(int32_t x, int32_t y) const {
1382- if (x < 0 || y < 0)
1383- return Widelands::INVALID_INDEX;
1384-
1385- unsigned int i = x / (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X);
1386- unsigned int j = y / (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + WARE_MENU_PIC_PAD_Y);
1387+ // Graphical offset
1388+ x -= 2;
1389+ y -= 2;
1390+
1391+ if (x < 0 || y < 0) {
1392+ return Widelands::INVALID_INDEX;
1393+ }
1394+
1395+ int i = x / (kWareMenuPicWidth + hgap_);
1396+ int j = y / (kWareMenuPicHeight + kWareMenuInfoSize + vgap_);
1397+ if (kWareMenuPicWidth * (i + 1) + hgap_ * i < x ||
1398+ (kWareMenuPicHeight + kWareMenuInfoSize) * (j + 1) + vgap_ * j < y) {
1399+ // Not on the ware, but on the space between
1400+ return Widelands::INVALID_INDEX;
1401+ }
1402 if (horizontal_) {
1403- unsigned int s = i;
1404+ int s = i;
1405 i = j;
1406 j = s;
1407 }
1408- if (i < icons_order().size() && j < icons_order()[i].size()) {
1409- const Widelands::DescriptionIndex& ware = icons_order()[i][j];
1410- assert(hidden_.count(ware) == 1);
1411- if (!(hidden_.find(ware)->second)) {
1412- return ware;
1413+ for (const auto& pair : icons_order_coords()) {
1414+ if (pair.second.x == i && pair.second.y == j) {
1415+ assert(hidden_.count(pair.first) == 1);
1416+ if (!(hidden_.find(pair.first)->second)) {
1417+ return pair.first;
1418+ }
1419+ break;
1420 }
1421 }
1422
1423@@ -199,15 +259,13 @@
1424 Vector2i anchor_pos = ware_position(selection_anchor_);
1425 // Add an offset to make sure the anchor line and column will be
1426 // selected when selecting in topleft direction
1427- int32_t anchor_x = anchor_pos.x + WARE_MENU_PIC_WIDTH / 2;
1428- int32_t anchor_y = anchor_pos.y + WARE_MENU_PIC_HEIGHT / 2;
1429+ int32_t anchor_x = anchor_pos.x + kWareMenuPicWidth / 2;
1430+ int32_t anchor_y = anchor_pos.y + kWareMenuPicHeight / 2;
1431
1432- unsigned int left_ware_idx = anchor_x / (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X);
1433- unsigned int top_ware_idx =
1434- anchor_y / (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + WARE_MENU_PIC_PAD_Y);
1435- unsigned int right_ware_idx = x / (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X);
1436- unsigned int bottoware_idx_ =
1437- y / (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + WARE_MENU_PIC_PAD_Y);
1438+ unsigned int left_ware_idx = anchor_x / (kWareMenuPicWidth + hgap_);
1439+ unsigned int top_ware_idx = anchor_y / (kWareMenuPicHeight + kWareMenuInfoSize + vgap_);
1440+ unsigned int right_ware_idx = x / (kWareMenuPicWidth + hgap_);
1441+ unsigned int bottoware_idx_ = y / (kWareMenuPicHeight + kWareMenuInfoSize + vgap_);
1442 unsigned int tmp;
1443
1444 // Reverse col/row and anchor/endpoint if needed
1445@@ -271,26 +329,43 @@
1446 NEVER_HERE();
1447 }
1448
1449-const Widelands::TribeDescr::WaresOrderCoords& AbstractWaresDisplay::icons_order_coords() const {
1450- switch (type_) {
1451- case Widelands::wwWARE:
1452- return tribe_.wares_order_coords();
1453- case Widelands::wwWORKER:
1454- return tribe_.workers_order_coords();
1455+const WaresOrderCoords& AbstractWaresDisplay::icons_order_coords() const {
1456+ assert(!order_coords_.empty());
1457+ return order_coords_;
1458+}
1459+
1460+void AbstractWaresDisplay::relayout_icons_order_coords() {
1461+ order_coords_.clear();
1462+ const int column_number = icons_order().size();
1463+ const int column_max_size = (g_gr->get_yres() - 290) / (kWareMenuPicHeight + vgap_ + kWareMenuInfoSize);
1464+
1465+ int16_t column_index_to_apply = 0;
1466+ for (int16_t column_index = 0; column_index < column_number; ++column_index) {
1467+ const std::vector<Widelands::DescriptionIndex>& column = icons_order().at(column_index);
1468+ const int row_number = column.size();
1469+ int16_t row_index_to_apply = 0;
1470+ for (int16_t row_index = 0; row_index < row_number; ++row_index) {
1471+ order_coords_.emplace(column.at(row_index), Widelands::Coords(column_index_to_apply, row_index_to_apply));
1472+ ++row_index_to_apply;
1473+ if (row_index_to_apply > column_max_size) {
1474+ row_index_to_apply = 0;
1475+ ++column_index_to_apply;
1476+ }
1477+ }
1478+ if (row_index_to_apply > 0) {
1479+ ++column_index_to_apply;
1480+ }
1481 }
1482- NEVER_HERE();
1483 }
1484
1485 Vector2i AbstractWaresDisplay::ware_position(Widelands::DescriptionIndex id) const {
1486 Vector2i p(2, 2);
1487 if (horizontal_) {
1488- p.x += icons_order_coords()[id].second * (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X);
1489- p.y += icons_order_coords()[id].first *
1490- (WARE_MENU_PIC_HEIGHT + WARE_MENU_PIC_PAD_Y + WARE_MENU_INFO_SIZE);
1491+ p.x += icons_order_coords().at(id).y * (kWareMenuPicWidth + hgap_);
1492+ p.y += icons_order_coords().at(id).x * (kWareMenuPicHeight + vgap_ + kWareMenuInfoSize);
1493 } else {
1494- p.x += icons_order_coords()[id].first * (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X);
1495- p.y += icons_order_coords()[id].second *
1496- (WARE_MENU_PIC_HEIGHT + WARE_MENU_PIC_PAD_Y + WARE_MENU_INFO_SIZE);
1497+ p.x += icons_order_coords().at(id).x * (kWareMenuPicWidth + hgap_);
1498+ p.y += icons_order_coords().at(id).y * (kWareMenuPicHeight + vgap_ + kWareMenuInfoSize);
1499 }
1500 return p;
1501 }
1502@@ -326,15 +401,15 @@
1503 const Image* icon = type_ == Widelands::wwWORKER ? tribe_.get_worker_descr(id)->icon() :
1504 tribe_.get_ware_descr(id)->icon();
1505
1506- dst.blit(p + Vector2i((w - WARE_MENU_PIC_WIDTH) / 2, 1), icon);
1507+ dst.blit(p + Vector2i((w - kWareMenuPicWidth) / 2, 1), icon);
1508
1509- dst.fill_rect(Recti(p + Vector2i(0, WARE_MENU_PIC_HEIGHT), w, WARE_MENU_INFO_SIZE),
1510+ dst.fill_rect(Recti(p + Vector2i(0, kWareMenuPicHeight), w, kWareMenuInfoSize),
1511 info_color_for_ware(id));
1512
1513 std::shared_ptr<const UI::RenderedText> rendered_text =
1514 UI::g_fh->render(as_waresinfo(info_for_ware(id)));
1515 rendered_text->draw(dst, Vector2i(p.x + w - rendered_text->width() - 1,
1516- p.y + WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + 1 -
1517+ p.y + kWareMenuPicHeight + kWareMenuInfoSize + 1 -
1518 rendered_text->height()));
1519 }
1520
1521
1522=== modified file 'src/wui/waresdisplay.h'
1523--- src/wui/waresdisplay.h 2019-02-23 11:00:49 +0000
1524+++ src/wui/waresdisplay.h 2019-05-06 13:51:46 +0000
1525@@ -20,6 +20,7 @@
1526 #ifndef WL_WUI_WARESDISPLAY_H
1527 #define WL_WUI_WARESDISPLAY_H
1528
1529+#include <memory>
1530 #include <vector>
1531
1532 #include "logic/map_objects/tribes/tribe_descr.h"
1533@@ -36,6 +37,8 @@
1534 struct WareList;
1535 } // namespace Widelands
1536
1537+using WaresOrderCoords = std::map<Widelands::DescriptionIndex, Widelands::Coords>;
1538+
1539 /**
1540 * Display wares or workers together with some string (typically a number)
1541 * in the style of the @ref WarehouseWindow.
1542@@ -54,7 +57,9 @@
1543 CLANG_DIAG_OFF("-Wunknown-pragmas") CLANG_DIAG_OFF("-Wzero-as-null-pointer-constant")
1544 boost::function<void(Widelands::DescriptionIndex, bool)> callback_function = 0,
1545 CLANG_DIAG_ON("-Wzero-as-null-pointer-constant")
1546- CLANG_DIAG_ON("-Wunknown-pragmas") bool horizontal = false);
1547+ CLANG_DIAG_ON("-Wunknown-pragmas") bool horizontal = false,
1548+ int32_t hgap = 3,
1549+ int32_t vgap = 4);
1550
1551 bool
1552 handle_mousemove(uint8_t state, int32_t x, int32_t y, int32_t xdiff, int32_t ydiff) override;
1553@@ -74,6 +79,19 @@
1554 return type_;
1555 }
1556
1557+ int32_t get_hgap() {
1558+ return hgap_;
1559+ }
1560+ int32_t get_vgap() {
1561+ return vgap_;
1562+ }
1563+ void set_hgap(int32_t);
1564+ void set_vgap(int32_t);
1565+
1566+ Widelands::Extent get_extent() const;
1567+
1568+ const WaresOrderCoords& icons_order_coords() const;
1569+
1570 protected:
1571 void layout() override;
1572
1573@@ -82,7 +100,6 @@
1574 virtual RGBColor info_color_for_ware(Widelands::DescriptionIndex);
1575
1576 const Widelands::TribeDescr::WaresOrder& icons_order() const;
1577- const Widelands::TribeDescr::WaresOrderCoords& icons_order_coords() const;
1578 virtual Vector2i ware_position(Widelands::DescriptionIndex) const;
1579 void draw(RenderTarget&) override;
1580 virtual void draw_ware(RenderTarget&, Widelands::DescriptionIndex);
1581@@ -110,6 +127,13 @@
1582 WareListSelectionType in_selection_; // Wares in temporary anchored selection
1583 bool selectable_;
1584 bool horizontal_;
1585+ int32_t hgap_;
1586+ int32_t vgap_;
1587+
1588+ WaresOrderCoords order_coords_;
1589+
1590+ void relayout_icons_order_coords();
1591+ void recalc_desired_size(bool);
1592
1593 /**
1594 * The ware on which the mouse press has been performed.
1595@@ -117,6 +141,8 @@
1596 */
1597 Widelands::DescriptionIndex selection_anchor_;
1598 boost::function<void(Widelands::DescriptionIndex, bool)> callback_function_;
1599+
1600+ std::unique_ptr<Notifications::Subscriber<GraphicResolutionChanged>> graphic_resolution_changed_subscriber_;
1601 };
1602
1603 /*

Subscribers

People subscribed via source and target branches

to status/vote changes: