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

Proposed by cghislai on 2013-07-14
Status: Merged
Merged at revision: 6654
Proposed branch: lp:~widelands-dev/widelands/csite_improvement
Merge into: lp:widelands
Diff against target: 599 lines (+260/-61)
11 files modified
src/constants.h (+5/-3)
src/logic/building.h (+1/-1)
src/logic/constructionsite.cc (+18/-11)
src/logic/item_ware_descr.h (+2/-0)
src/logic/productionsite.cc (+50/-25)
src/logic/productionsite.h (+1/-1)
src/ui_basic/table.cc (+4/-0)
src/wui/building_ui.cc (+4/-1)
src/wui/buildingwindow.cc (+10/-2)
src/wui/waresdisplay.cc (+146/-15)
src/wui/waresdisplay.h (+19/-2)
To merge this branch: bzr merge lp:~widelands-dev/widelands/csite_improvement
Reviewer Review Type Date Requested Status
SirVer 2013-07-14 Approve on 2013-07-21
Review via email: mp+174623@code.launchpad.net

Description of the change

This contains a bunch of improvements not all related to construction sites
- Colored string for production efficiency and trends
- Anchored selection for ware selection in warehouses/economy settings
- Range of building shown for construction sites
- Building name shown in construction site windows
- Building window opened when construction site window was open and construction ended

To post a comment you must log in.
SirVer (sirver) wrote :

I'll try to have a look at this during this week - I will be a bit busy though, so no promises. If anybody else can review this, go ahead of course :).

6625. By cghislai on 2013-07-15

Small fixes

6626. By SirVer on 2013-07-17

Review with a few comments.

SirVer (sirver) wrote :

Okay, a bunch of minor comments. I did not understand what the anchoring does - I would love to see some comments about this someplace.

review: Needs Fixing
SirVer (sirver) wrote :

And I forgot to mention: I much appreciate you adding {} in more places while going over the code :). I find this so much more readable.

6627. By cghislai on 2013-07-17

Added comments and fixed some things

6628. By cghislai on 2013-07-19

Merge trunk

cghislai (charlyghislain) wrote :

I loaclly merged the bug657285 branch in order to test this under opengl without crashing.
Everything works as intended.

6629. By cghislai on 2013-07-21

Merge trunk

6630. By SirVer on 2013-07-21

Merged trunk.

6631. By SirVer on 2013-07-21

Small nit fix.

SirVer (sirver) wrote :

Lgtm. I fixed very small nits and merged this.

review: Approve
SirVer (sirver) wrote :

Charly, could you go over the bugs and mark them fixed as appropriate?

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/constants.h'
2--- src/constants.h 2013-07-16 00:37:26 +0000
3+++ src/constants.h 2013-07-21 14:41:26 +0000
4@@ -80,9 +80,11 @@
5 #define PROSA_FONT_CLR_FG RGBColor(255, 255, 0)
6
7 /// Colors for good/ok/bad
8-#define UI_FONT_CLR_BAD_HEX "ff0000"
9-#define UI_FONT_CLR_OK_HEX "ffff00"
10-#define UI_FONT_CLR_GOOD_HEX "325b1f"
11+#define UI_FONT_CLR_BRIGHT_HEX "fffaaa"
12+#define UI_FONT_CLR_DARK_HEX "a39013"
13+#define UI_FONT_CLR_BAD_HEX "bb0000"
14+#define UI_FONT_CLR_OK_HEX "ffe11e"
15+#define UI_FONT_CLR_GOOD_HEX "00bb00"
16 //@}
17
18 /** \name Text colors
19
20=== modified file 'src/logic/building.h'
21--- src/logic/building.h 2013-07-16 10:17:53 +0000
22+++ src/logic/building.h 2013-07-21 14:41:26 +0000
23@@ -184,7 +184,7 @@
24 virtual bool burn_on_destroy();
25 virtual void destroy(Editor_Game_Base &);
26
27- void show_options(Interactive_GameBase &, bool avoid_fastclick = false);
28+ void show_options(Interactive_GameBase &, bool avoid_fastclick = false, Point pos = Point(- 1, - 1));
29 void hide_options();
30 void refresh_options(Interactive_GameBase &);
31
32
33=== modified file 'src/logic/constructionsite.cc'
34--- src/logic/constructionsite.cc 2013-07-18 06:31:11 +0000
35+++ src/logic/constructionsite.cc 2013-07-21 14:41:26 +0000
36@@ -25,12 +25,14 @@
37 #include "upcast.h"
38 #include "wexception.h"
39
40-#include "graphic/animation.h"
41 #include "economy/wares_queue.h"
42 #include "game.h"
43+#include "graphic/animation.h"
44 #include "graphic/graphic.h"
45 #include "graphic/rendertarget.h"
46 #include "sound/sound_handler.h"
47+#include "ui_basic/window.h"
48+#include "wui/interactive_gamebase.h"
49 #include "tribe.h"
50 #include "worker.h"
51
52@@ -86,14 +88,9 @@
53 std::string ConstructionSite::get_statistics_string()
54 {
55 unsigned int percent = (get_built_per64k() * 100) >> 16;
56-
57- std::string clr = UI_FONT_CLR_OK_HEX;
58- if (percent <= 25) clr = UI_FONT_CLR_BAD_HEX;
59- else if (percent >= 75) clr = UI_FONT_CLR_GOOD_HEX;
60-
61- std::string perc_s = (boost::format("<font color=%s>%i</font>") % clr % percent).str();
62-
63- return (boost::format(_("%s%% built")) % perc_s.c_str()).str();
64+ std::string perc_s =
65+ (boost::format("<font color=%1$s>%2$i%% built</font>") % UI_FONT_CLR_DARK_HEX % percent).str();
66+ return perc_s;
67 }
68
69 /*
70@@ -102,9 +99,11 @@
71 =======
72 */
73 WaresQueue & ConstructionSite::waresqueue(Ware_Index const wi) {
74- container_iterate_const(Wares, m_wares, i)
75- if ((*i.current)->get_ware() == wi)
76+ container_iterate_const(Wares, m_wares, i) {
77+ if ((*i.current)->get_ware() == wi) {
78 return **i.current;
79+ }
80+ }
81 throw wexception
82 ("%s (%u) (building %s) has no WaresQueue for %u",
83 name().c_str(), serial(), m_building->name().c_str(), wi.value());
84@@ -183,6 +182,14 @@
85 builder->reset_tasks(ref_cast<Game, Editor_Game_Base>(egbase));
86 builder->set_location(&b);
87 }
88+ // Open the new building window if needed
89+ if (m_optionswindow) {
90+ Point window_position = m_optionswindow->get_pos();
91+ hide_options();
92+ Interactive_GameBase & igbase =
93+ ref_cast<Interactive_GameBase, Interactive_Base>(*egbase.get_ibase());
94+ b.show_options(igbase, false, window_position);
95+ }
96 }
97 }
98
99
100=== modified file 'src/logic/item_ware_descr.h'
101--- src/logic/item_ware_descr.h 2013-02-10 19:36:24 +0000
102+++ src/logic/item_ware_descr.h 2013-07-21 14:41:26 +0000
103@@ -36,6 +36,8 @@
104
105 #define WARE_MENU_PIC_WIDTH 24 //< Default width for ware's menu icons
106 #define WARE_MENU_PIC_HEIGHT 24 //< Default height for ware's menu icons
107+#define WARE_MENU_PIC_PAD_X 3 //< Default padding between menu icons
108+#define WARE_MENU_PIC_PAD_Y 4 //< Default padding between menu icons
109
110 namespace Widelands {
111
112
113=== modified file 'src/logic/productionsite.cc'
114--- src/logic/productionsite.cc 2013-07-18 16:47:56 +0000
115+++ src/logic/productionsite.cc 2013-07-21 14:41:26 +0000
116@@ -18,6 +18,7 @@
117 */
118
119 #include <libintl.h>
120+#include <boost/format.hpp>
121
122 #include "helper.h"
123 #include "i18n.h"
124@@ -242,21 +243,23 @@
125 uint32_t nr_workers = 0;
126 for (uint32_t i = nr_working_positions; i;)
127 nr_workers += m_working_positions[--i].worker ? 1 : 0;
128- if (!nr_workers)
129- return _("(not occupied)");
130- else if (uint32_t const nr_requests = nr_working_positions - nr_workers) {
131- char buffer[1000];
132- snprintf
133- (buffer, sizeof(buffer), "%s",
134- ngettext("Worker missing", "Workers missing", nr_requests));
135- return buffer;
136+ if (!nr_workers) {
137+ return
138+ (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_BAD_HEX % _("(not occupied)")).str();
139+ } else if (uint32_t const nr_requests = nr_working_positions - nr_workers) {
140+ return
141+ (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_BAD_HEX %
142+ ngettext(_("Worker missing"), _("Workers missing"), nr_requests))
143+ .str();
144 }
145
146- if (m_statistics_changed)
147+ if (m_statistics_changed) {
148 calc_statistics();
149+ }
150
151- if (m_is_stopped)
152- return _("(stopped)");
153+ if (m_is_stopped) {
154+ return (boost::format("<font color=%s>%s</font>") % UI_FONT_CLR_BRIGHT_HEX % _("(stopped)")).str();
155+ }
156
157 return m_statistics_buffer;
158 }
159@@ -315,21 +318,43 @@
160 ++lastOk;
161 }
162 }
163- uint8_t const percOk = (ok * 100) / STATISTICS_VECTOR_LENGTH;
164- uint8_t const lastPercOk = (lastOk * 100) / (STATISTICS_VECTOR_LENGTH / 2);
165-
166- const std::string trend =
167- lastPercOk > percOk ? "+" : lastPercOk < percOk ? "-" : "=";
168-
169- if (0 < percOk and percOk < 100)
170- snprintf
171- (m_statistics_buffer, sizeof(m_statistics_buffer),
172- "%d%% %s", percOk, trend.c_str());
173+ // Somehow boost::format doesn't handle correctly uint8_t in this case
174+ unsigned int percOk = (ok * 100) / STATISTICS_VECTOR_LENGTH;
175+ unsigned int lastPercOk = (lastOk * 100) / (STATISTICS_VECTOR_LENGTH / 2);
176+
177+ std::string color;
178+ if (percOk < 33)
179+ color = UI_FONT_CLR_BAD_HEX;
180+ else if (percOk < 66)
181+ color = UI_FONT_CLR_OK_HEX;
182 else
183- snprintf
184- (m_statistics_buffer, sizeof(m_statistics_buffer),
185- "%d%%", percOk);
186-
187+ color = UI_FONT_CLR_GOOD_HEX;
188+ const std::string perc_str =
189+ (boost::format("<font color=%1$s>%2$i%%</font>") % color % percOk).str();
190+
191+ std::string trend;
192+ if (lastPercOk > percOk) {
193+ color = UI_FONT_CLR_GOOD_HEX;
194+ trend = "+";
195+ } else if (lastPercOk < percOk) {
196+ color = UI_FONT_CLR_BAD_HEX;
197+ trend = "-";
198+ } else {
199+ color = UI_FONT_CLR_BRIGHT_HEX;
200+ trend = "=";
201+ }
202+ const std::string trend_str =
203+ (boost::format("<font color=%s>%s</font>") % color % trend).str();
204+
205+ if (0 < percOk and percOk < 100) {
206+ snprintf
207+ (m_statistics_buffer, sizeof(m_statistics_buffer),
208+ "%s %s", perc_str.c_str(), trend_str.c_str());
209+ } else {
210+ snprintf
211+ (m_statistics_buffer, sizeof(m_statistics_buffer),
212+ "%s", perc_str.c_str());
213+ }
214 m_last_stat_percent = percOk;
215
216 m_statistics_changed = false;
217
218=== modified file 'src/logic/productionsite.h'
219--- src/logic/productionsite.h 2013-04-22 20:15:00 +0000
220+++ src/logic/productionsite.h 2013-07-21 14:41:26 +0000
221@@ -256,7 +256,7 @@
222 Input_Queues m_input_queues; ///< input queues for all inputs
223 std::vector<bool> m_statistics;
224 bool m_statistics_changed;
225- char m_statistics_buffer[40];
226+ char m_statistics_buffer[128];
227 char m_result_buffer [213];
228 uint8_t m_last_stat_percent;
229 bool m_is_stopped;
230
231=== modified file 'src/ui_basic/table.cc'
232--- src/ui_basic/table.cc 2013-07-21 08:25:22 +0000
233+++ src/ui_basic/table.cc 2013-07-21 14:41:26 +0000
234@@ -293,6 +293,10 @@
235 point.x += picw;
236 }
237
238+ if (entry_string.empty()) {
239+ curx += curw;
240+ continue;
241+ }
242 const Image* entry_text_im = UI::g_fh1->render(as_uifont(entry_string, m_fontsize));
243 uint16_t text_width = entry_text_im->width();
244 if (alignment & Align_Right) {
245
246=== modified file 'src/wui/building_ui.cc'
247--- src/wui/building_ui.cc 2013-07-21 08:25:22 +0000
248+++ src/wui/building_ui.cc 2013-07-21 14:41:26 +0000
249@@ -30,7 +30,7 @@
250 * Create the building's options window if necessary and bring it to
251 * the top to be seen by the player.
252 */
253-void Building::show_options(Interactive_GameBase & igbase, bool avoid_fastclick)
254+void Building::show_options(Interactive_GameBase & igbase, bool avoid_fastclick, Point pos)
255 {
256 if (m_optionswindow) {
257 if (m_optionswindow->is_minimal())
258@@ -45,6 +45,9 @@
259 // get properly initialized
260 m_optionswindow->think();
261 }
262+ if (pos.x >= 0 && pos.y >= 0) {
263+ m_optionswindow->set_pos(pos);
264+ }
265 }
266
267 /**
268
269=== modified file 'src/wui/buildingwindow.cc'
270--- src/wui/buildingwindow.cc 2013-07-21 08:25:22 +0000
271+++ src/wui/buildingwindow.cc 2013-07-21 14:41:26 +0000
272@@ -23,6 +23,7 @@
273 #include "graphic/image.h"
274 #include "graphic/rendertarget.h"
275 #include "interactive_player.h"
276+#include "logic/constructionsite.h"
277 #include "logic/dismantlesite.h"
278 #include "logic/maphollowregion.h"
279 #include "logic/militarysite.h"
280@@ -35,8 +36,9 @@
281 #include "upcast.h"
282 #include "waresqueuedisplay.h"
283
284+#include <boost/format.hpp>
285+
286 #include "buildingwindow.h"
287-#include "logic/militarysite.h"
288
289 static const char * pic_bulldoze = "pics/menu_bld_bulldoze.png";
290 static const char * pic_dismantle = "pics/menu_bld_dismantle.png";
291@@ -78,10 +80,16 @@
292
293 set_center_panel(vbox);
294 set_think(true);
295+ set_fastclick_panel(this);
296
297 show_workarea();
298
299- set_fastclick_panel(this);
300+ // Title for construction site
301+ if (upcast(Widelands::ConstructionSite, csite, &m_building)) {
302+ // Show name in parenthesis as it may take all width already
303+ const std::string title = (boost::format("(%s)") % csite->building().descname()).str();
304+ set_title(title);
305+ }
306 }
307
308
309
310=== modified file 'src/wui/waresdisplay.cc'
311--- src/wui/waresdisplay.cc 2013-03-01 23:12:08 +0000
312+++ src/wui/waresdisplay.cc 2013-07-21 14:41:26 +0000
313@@ -63,12 +63,16 @@
314 m_hidden
315 (m_type == Widelands::wwWORKER ? m_tribe.get_nrworkers()
316 : m_tribe.get_nrwares(), false),
317+ m_in_selection
318+ (m_type == Widelands::wwWORKER ? m_tribe.get_nrworkers()
319+ : m_tribe.get_nrwares(), false),
320 m_selectable(selectable),
321 m_horizontal(horizontal),
322+ m_selection_anchor(Widelands::Ware_Index::Null()),
323 m_callback_function(callback_function)
324 {
325 //resize the configuration of our wares if they won't fit in the current window
326- int number = (g_gr->get_yres() - 160) / (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + 3);
327+ int number = (g_gr->get_yres() - 160) / (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + WARE_MENU_PIC_PAD_Y);
328 const_cast<Widelands::Tribe_Descr &>(m_tribe).resize_ware_orders(number);
329
330 // Find out geometry from icons_order
331@@ -85,13 +89,13 @@
332
333 // 25 is height of m_curware text
334 set_desired_size
335- (columns * (WARE_MENU_PIC_WIDTH + 3) + 1,
336- rows * (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + 3) + 1 + 25);
337+ (columns * (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X) + 1,
338+ rows * (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + WARE_MENU_PIC_PAD_Y) + 1 + 25);
339 }
340
341
342 bool AbstractWaresDisplay::handle_mousemove
343- (uint8_t, int32_t x, int32_t y, int32_t, int32_t)
344+ (uint8_t state, int32_t x, int32_t y, int32_t, int32_t)
345 {
346 const Widelands::Ware_Index index = ware_at_point(x, y);
347
348@@ -104,6 +108,17 @@
349 .c_str()
350 :
351 "");
352+ if (m_selection_anchor) {
353+ // Ensure mouse button is still pressed as some
354+ // mouse release events do not reach us
355+ if (state ^ SDL_BUTTON_LMASK) {
356+ // FIXME: We should call another function that will not pass that events
357+ // to our Panel superclass
358+ handle_mouserelease(SDL_BUTTON_LEFT, x, y);
359+ return true;
360+ }
361+ update_anchor_selection(x, y);
362+ }
363 return true;
364 }
365
366@@ -112,11 +127,19 @@
367 {
368 if (btn == SDL_BUTTON_LEFT) {
369 Widelands::Ware_Index ware = ware_at_point(x, y);
370- if (!ware)
371+ if (!ware) {
372 return false;
373-
374- if (m_selectable) {
375- toggle_ware(ware);
376+ }
377+ if (!m_selectable) {
378+ return true;
379+ }
380+ if (!m_selection_anchor) {
381+ // Create the selection anchor to be able to select
382+ // multiple ware by dragging.
383+ m_selection_anchor = ware;
384+ m_in_selection[ware] = true;
385+ } else {
386+ // A mouse release has been missed
387 }
388 return true;
389 }
390@@ -124,6 +147,35 @@
391 return UI::Panel::handle_mousepress(btn, x, y);
392 }
393
394+bool AbstractWaresDisplay::handle_mouserelease(Uint8 btn, int32_t x, int32_t y)
395+{
396+ if (btn != SDL_BUTTON_LEFT || !m_selection_anchor) {
397+ return UI::Panel::handle_mouserelease(btn, x, y);
398+ }
399+
400+ Widelands::Ware_Index const number =
401+ m_type == Widelands::wwWORKER ? m_tribe.get_nrworkers() : m_tribe.get_nrwares();
402+
403+ bool to_be_selected = !ware_selected(m_selection_anchor);
404+ for (Widelands::Ware_Index i = Widelands::Ware_Index::First(); i < number; ++i)
405+ {
406+ if (!m_in_selection[i]) {
407+ continue;
408+ }
409+ if (to_be_selected) {
410+ select_ware(i);
411+ } else {
412+ unselect_ware(i);
413+ }
414+ }
415+
416+ // Release anchor, empty selection
417+ m_selection_anchor = Widelands::Ware_Index::Null();
418+ std::fill(m_in_selection.begin(), m_in_selection.end(), false);
419+ return true;
420+}
421+
422+
423 /**
424 * Returns the index of the ware under the given coordinates, or
425 * WareIndex::Null() if the given point is outside the range.
426@@ -134,8 +186,8 @@
427 return Widelands::Ware_Index::Null();
428
429
430- unsigned int i = x / (WARE_MENU_PIC_WIDTH + 4);
431- unsigned int j = y / (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + 3);
432+ unsigned int i = x / (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X);
433+ unsigned int j = y / (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + WARE_MENU_PIC_PAD_Y);
434 if (m_horizontal) {
435 unsigned int s = i;
436 i = j;
437@@ -151,6 +203,68 @@
438 return Widelands::Ware_Index::Null();
439 }
440
441+// Update the anchored selection. An anchor has been created by mouse
442+// press. Mouse move call this function with the current mouse position.
443+// This function will temporary store all wares in the rectangle between anchor
444+// and current pos to allow their selection on mouse release
445+void AbstractWaresDisplay::update_anchor_selection(int32_t x, int32_t y)
446+{
447+ if (!m_selection_anchor || x < 0 || y < 0) {
448+ return;
449+ }
450+
451+ std::fill(m_in_selection.begin(), m_in_selection.end(), false);
452+ Point anchor_pos = ware_position(m_selection_anchor);
453+ // Add an offset to make sure the anchor line and column will be
454+ // selected when selecting in topleft direction
455+ int32_t anchor_x = anchor_pos.x + WARE_MENU_PIC_WIDTH / 2;
456+ int32_t anchor_y = anchor_pos.y + WARE_MENU_PIC_HEIGHT / 2;
457+
458+ unsigned int left_ware_idx = anchor_x / (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X);
459+ unsigned int top_ware_idx = anchor_y / (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + WARE_MENU_PIC_PAD_Y);
460+ unsigned int right_ware_idx = x / (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X);
461+ unsigned int bottom_ware_idx = y / (WARE_MENU_PIC_HEIGHT + WARE_MENU_INFO_SIZE + WARE_MENU_PIC_PAD_Y);
462+ unsigned int tmp;
463+
464+ // Reverse col/row and anchor/endpoint if needed
465+ if (m_horizontal) {
466+ tmp = left_ware_idx;
467+ left_ware_idx = top_ware_idx;
468+ top_ware_idx = tmp;
469+ tmp = right_ware_idx;
470+ right_ware_idx = bottom_ware_idx;
471+ bottom_ware_idx = tmp;
472+ }
473+ if (left_ware_idx > right_ware_idx) {
474+ tmp = left_ware_idx;
475+ left_ware_idx = right_ware_idx;
476+ right_ware_idx = tmp;
477+ }
478+ if (top_ware_idx > bottom_ware_idx) {
479+ tmp = top_ware_idx;
480+ top_ware_idx = bottom_ware_idx;
481+ bottom_ware_idx = tmp;
482+ }
483+
484+ for (unsigned int cur_ware_x = left_ware_idx; cur_ware_x <= right_ware_idx; cur_ware_x++) {
485+ if (cur_ware_x >= icons_order().size()) {
486+ continue;
487+ }
488+ for (unsigned cur_ware_y = top_ware_idx; cur_ware_y <= bottom_ware_idx; cur_ware_y++) {
489+ if (cur_ware_y >= icons_order()[cur_ware_x].size()) {
490+ continue;
491+ }
492+ Widelands::Ware_Index ware = icons_order()[cur_ware_x][cur_ware_y];
493+ if (m_hidden[ware]) {
494+ continue;
495+ }
496+ m_in_selection[ware] = true;
497+ }
498+ }
499+ update();
500+}
501+
502+
503
504 void AbstractWaresDisplay::layout()
505 {
506@@ -219,11 +333,15 @@
507 {
508 Point p(2, 2);
509 if (m_horizontal) {
510- p.x += icons_order_coords()[id].second * (WARE_MENU_PIC_WIDTH + 3);
511- p.y += icons_order_coords()[id].first * (WARE_MENU_PIC_HEIGHT + 3 + WARE_MENU_INFO_SIZE);
512+ p.x += icons_order_coords()[id].second *
513+ (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X);
514+ p.y += icons_order_coords()[id].first *
515+ (WARE_MENU_PIC_HEIGHT + WARE_MENU_PIC_PAD_Y + WARE_MENU_INFO_SIZE);
516 } else {
517- p.x += icons_order_coords()[id].first * (WARE_MENU_PIC_WIDTH + 3);
518- p.y += icons_order_coords()[id].second * (WARE_MENU_PIC_HEIGHT + 3 + WARE_MENU_INFO_SIZE);
519+ p.x += icons_order_coords()[id].first *
520+ (WARE_MENU_PIC_WIDTH + WARE_MENU_PIC_PAD_X);
521+ p.y += icons_order_coords()[id].second *
522+ (WARE_MENU_PIC_HEIGHT + WARE_MENU_PIC_PAD_Y + WARE_MENU_INFO_SIZE);
523 }
524 return p;
525 }
526@@ -241,9 +359,21 @@
527 {
528 Point p = ware_position(id);
529
530+ bool draw_selected = m_selected[id];
531+ if (m_selection_anchor) {
532+ // Draw the temporary selected wares as if they were
533+ // selected.
534+ // TODO: Use another pic for the temporary selection
535+ if (!ware_selected(m_selection_anchor)) {
536+ draw_selected |= m_in_selection[id];
537+ } else {
538+ draw_selected &= !m_in_selection[id];
539+ }
540+ }
541+
542 // draw a background
543 const Image* bgpic =
544- g_gr->images().get(ware_selected(id) ? "pics/ware_list_bg_selected.png" : "pics/ware_list_bg.png");
545+ g_gr->images().get(draw_selected ? "pics/ware_list_bg_selected.png" : "pics/ware_list_bg.png");
546 uint16_t w = bgpic->width();
547
548 dst.blit(p, bgpic);
549@@ -378,3 +508,4 @@
550 }
551 return ret;
552 }
553+
554
555=== modified file 'src/wui/waresdisplay.h'
556--- src/wui/waresdisplay.h 2013-07-21 08:25:22 +0000
557+++ src/wui/waresdisplay.h 2013-07-21 14:41:26 +0000
558@@ -56,9 +56,8 @@
559
560 bool handle_mousemove
561 (uint8_t state, int32_t x, int32_t y, int32_t xdiff, int32_t ydiff);
562-
563 bool handle_mousepress(uint8_t btn, int32_t x, int32_t y);
564-
565+ bool handle_mouserelease(Uint8 btn, int32_t x, int32_t y);
566
567 // Wares may be selected (highlighted)
568 void select_ware(Widelands::Ware_Index);
569@@ -100,13 +99,31 @@
570 typedef std::vector<const Widelands::WareList *> vector_type;
571 typedef std::vector<bool> selection_type;
572
573+ /**
574+ * Update the anchored selection. When first mouse button is
575+ * pressed on a ware, it is stored in @ref m_selection_anchor.
576+ * Mouse moves trigger this function to select all wares items
577+ * in the rectangle between the anchor and the mouse position.
578+ * They are temporary stored in @ref m_in_selection.
579+ * Releasing the mouse button will performs the selection.
580+ * This allows selection of multiple wares by dragging.
581+ */
582+ void update_anchor_selection(int32_t x, int32_t y);
583+
584 const Widelands::Tribe_Descr & m_tribe;
585 Widelands::WareWorker m_type;
586 UI::Textarea m_curware;
587 selection_type m_selected;
588 selection_type m_hidden;
589+ selection_type m_in_selection; //Wares in temporary anchored selection
590 bool m_selectable;
591 bool m_horizontal;
592+
593+ /**
594+ * The ware on which the mouse press has been performed.
595+ * It is not selected directly, but will be on mouse release.
596+ */
597+ Widelands::Ware_Index m_selection_anchor;
598 boost::function<void(Widelands::Ware_Index, bool)> m_callback_function;
599 };
600