Merge lp:~widelands-dev/widelands/csite_improvement into lp:widelands
- csite_improvement
- Merge into trunk
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 | ||||||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
SirVer | Approve | ||
Review via email: mp+174623@code.launchpad.net |
Commit message
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
SirVer (sirver) wrote : | # |
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.
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.
cghislai (charlyghislain) wrote : | # |
I loaclly merged the bug657285 branch in order to test this under opengl without crashing.
Everything works as intended.
SirVer (sirver) wrote : | # |
Lgtm. I fixed very small nits and merged this.
SirVer (sirver) wrote : | # |
Charly, could you go over the bugs and mark them fixed as appropriate?
Preview Diff
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 |
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 :).