Merge lp:~widelands-dev/widelands/revise-map-descr into lp:widelands
- revise-map-descr
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 7990 |
Proposed branch: | lp:~widelands-dev/widelands/revise-map-descr |
Merge into: | lp:widelands |
Diff against target: |
788 lines (+281/-159) 16 files modified
src/editor/ui_menus/main_menu_load_or_save_map.cc (+2/-1) src/editor/ui_menus/main_menu_map_options.cc (+7/-6) src/graphic/text/rt_parse.cc (+1/-0) src/ui_basic/multilinetextarea.cc (+20/-12) src/ui_basic/multilinetextarea.h (+3/-1) src/ui_basic/scrollbar.cc (+3/-0) src/ui_fsmenu/launch_mpg.cc (+1/-1) src/ui_fsmenu/mapselect.cc (+23/-22) src/wui/CMakeLists.txt (+2/-0) src/wui/map_tags.cc (+60/-0) src/wui/map_tags.h (+35/-0) src/wui/mapdata.cc (+4/-3) src/wui/mapdetails.cc (+99/-83) src/wui/mapdetails.h (+10/-18) src/wui/suggested_teams_box.cc (+9/-9) src/wui/suggested_teams_box.h (+2/-3) |
To merge this branch: | bzr merge lp:~widelands-dev/widelands/revise-map-descr |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Miroslav Remák | code | Approve | |
kaputtnik (community) | testing | Approve | |
Review via email: mp+292031@code.launchpad.net |
Commit message
Revised map details in map loading screens. Localized map tags everywhere.
Description of the change
It became impossible to scroll through some map descriptions, so I put it all into one big richtext area. This means that I could also add some more info like map size and tags.
kaputtnik (franku) wrote : | # |
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 1016. State: failed. Details: https:/
Appveyor build 848. State: success. Details: https:/
GunChleoc (gunchleoc) wrote : | # |
1. Fixed
> 2. There are obsolete information: "Map size" and "2/3/4/... Player map".
> These information is always in the table, so why should we have it in the
> description again?
We also use this in Editor-> Save Map. Do you think the information is useless there as well? There are 3 ways we could go:
a. leave the info in
b. remove the info
c. distinguish between loading and saving contexts
3. How is it now?
> Just a side note:
Good idea, but not for Build 19 ;)
kaputtnik (franku) wrote : | # |
Got a crash when trying to access a folder in 'editor load map' and 'New game':
terminate called after throwing an instance of 'RT::SyntaxErro
what(): Syntax error at 1:65: expected an allowed tag, got 'parent'. String continues with: '<parent>
> 1. Fixed
Yeah :-)
> > 2. There are obsolete information: "Map size" and "2/3/4/... Player map".
> > These information is always in the table, so why should we have it in the
> > description again?
>
> We also use this in Editor-> Save Map. Do you think the information is useless
> there as well?
Yes, i think so. A mapmaker normally knows how much players he has placed on the map. The size of the map is mostly interesting when creating a new map because it has influence to max. number of players or shaping the terrain (how much unbuildable areas). And if a map is saved once, the size is shown in table. The size of the map is also shown in the Map options menu and as explained earlier i would prefer to make the Map Options be a part of the whole Map save process (i create a bug report for this idea).
So i would say:
> b. remove the info
> 3. How is it now?
Hm, maybe better but now there is a mix of coloring headers: Mapname, yellow; String "Author", white; Name of author yellow. If we think of Headers as static strings (Name of map, "Author", "Tags"...) and other texts as variable strings (Name of Author, List of tags, Text of description,...) i think all static texts should have the same color (f.e. yellow) and all variable texts should have the same color (f.e. white). The Name of the menu is also a static text and therefor should have the same color as other static texts. I believe making a distinction like this (static/variable texts) would bring some visual order to the menu. Having two colors is really good :-)
> > Just a side note:
>
> Good idea, but not for Build 19 ;)
Yes, of course ;)
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 1018. State: passed. Details: https:/
Appveyor build 850. State: success. Details: https:/
GunChleoc (gunchleoc) wrote : | # |
> b. remove the info
Done
3. A consistent color scheme is always good, but I don't think we can pull this off easily without doing a bigger overhaul. The colors have to fit for both dark and light backgrounds. So, I have removed the color from the headers and used some italic texts instead. How does it look to you now?
kaputtnik (franku) wrote : | # |
Hm, i don't know really. The two colored texts are better in my opinion. I have made some screenshots for a comparison and changed the code to use the bright gray color for "txt as_content": http://
Above left: Current trunk
Above right: This branch with italic
Middle left: Bright gray for "as_content"
Middle right: For comparison of bright gray with wooden background
Bottom: Load save game menu
I believe the main problematic thing is to visual distinguish between headers and the text. Currently this is made by having a colon after each header and indentation of content texts, which i like very much. Regarding the colon: "Suggested Teams" has it, and putting it after the other headers would help to distinguish, IMHO.
One other thing is disturbing: The second line. This shows either "Map", "Scenario" or "Directory" after the Name of the map/directory. The second line is not "self explaining". If one chooses different maps from the list there is always "Map" shown. So he/she may ask him/her self what does this "Map" mean? In current trunk this is better solved by having the strings "Map:", "Scenario:" and "Directory:" (with colon) as first line and the second line contains then the name of the map or the name of directory. This explains the second line instead in this branch there is no explaining.
I think the main problem for doing this branch is the suggested teams area, which needs a lot of space. Maybe we find another solution for this issue later on. F.e i could imagine to place suggested teams in the Launch Game menu... Just because it is then shown when the teams could be made. Currently the suggested teams could not be seen anymore where one has to make them. Future talk...
GunChleoc (gunchleoc) wrote : | # |
How is it now? We can't do indents at this time, so I'm using a color scheme again. I made separate layouts for the fullscreen and the editor menus.
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 1025. State: failed. Details: https:/
Appveyor build 857. State: success. Details: https:/
kaputtnik (franku) wrote : | # |
I think it's good now... maybe decrease the font size a bit in the load game menu?
There is now different coloring for headers in editor and load game, but the color scheme in editor is the same as for the help, so there is a consistent coloring "white headers on wooden background".
But my opinion is not the only valid one. Maybe someone else should tell his opinion? Asking in forum?
No crash discovered :-)
GunChleoc (gunchleoc) wrote : | # |
Decreasing the font size makes it harder to read, so I'd rather not.
Miroslav Remák (miroslavr256) wrote : | # |
Codecheck complains:
src/wui/
LGTM otherwise.
bunnybot (widelandsofficial) wrote : | # |
Bunnybot encountered an error while working on this merge proposal:
The read operation timed out
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 1025. State: failed. Details: https:/
Appveyor build 857. State: success. Details: https:/
GunChleoc (gunchleoc) wrote : | # |
Thanks!
@bunnybot merge
Preview Diff
1 | === modified file 'src/editor/ui_menus/main_menu_load_or_save_map.cc' |
2 | --- src/editor/ui_menus/main_menu_load_or_save_map.cc 2016-04-06 09:23:04 +0000 |
3 | +++ src/editor/ui_menus/main_menu_load_or_save_map.cc 2016-05-06 08:30:33 +0000 |
4 | @@ -48,7 +48,8 @@ |
5 | |
6 | table_(this, tablex_, tabley_, tablew_, tableh_, false), |
7 | map_details_( |
8 | - this, right_column_x_, tabley_, get_inner_w() - right_column_x_ - padding_, tableh_), |
9 | + this, right_column_x_, tabley_, get_inner_w() - right_column_x_ - padding_, tableh_, |
10 | + MapDetails::Style::kWui), |
11 | ok_(this, |
12 | "ok", |
13 | UI::g_fh1->fontset()->is_rtl() ? get_inner_w() / 2 - butw_ - padding_ : get_inner_w() / 2 + padding_, |
14 | |
15 | === modified file 'src/editor/ui_menus/main_menu_map_options.cc' |
16 | --- src/editor/ui_menus/main_menu_map_options.cc 2016-04-23 13:33:53 +0000 |
17 | +++ src/editor/ui_menus/main_menu_map_options.cc 2016-05-06 08:30:33 +0000 |
18 | @@ -33,6 +33,7 @@ |
19 | #include "ui_basic/multilineeditbox.h" |
20 | #include "ui_basic/multilinetextarea.h" |
21 | #include "ui_basic/textarea.h" |
22 | +#include "wui/map_tags.h" |
23 | |
24 | inline EditorInteractive & MainMenuMapOptions::eia() { |
25 | return dynamic_cast<EditorInteractive&>(*get_parent()); |
26 | @@ -122,12 +123,12 @@ |
27 | |
28 | |
29 | tags_box_.add(new UI::Textarea(&tags_box_, 0, 0, max_w_, labelh_, _("Tags:")), UI::Align::kLeft); |
30 | - add_tag_checkbox(&tags_box_, "unbalanced", _("Unbalanced")); |
31 | - add_tag_checkbox(&tags_box_, "ffa", _("Free for all")); |
32 | - add_tag_checkbox(&tags_box_, "1v1", _("1v1")); |
33 | - add_tag_checkbox(&tags_box_, "2teams", _("Teams of 2")); |
34 | - add_tag_checkbox(&tags_box_, "3teams", _("Teams of 3")); |
35 | - add_tag_checkbox(&tags_box_, "4teams", _("Teams of 4")); |
36 | + add_tag_checkbox(&tags_box_, "unbalanced", localize_tag("unbalanced")); |
37 | + add_tag_checkbox(&tags_box_, "ffa", localize_tag("ffa")); |
38 | + add_tag_checkbox(&tags_box_, "1v1", localize_tag("1v1")); |
39 | + add_tag_checkbox(&tags_box_, "2teams", localize_tag("2teams")); |
40 | + add_tag_checkbox(&tags_box_, "3teams", localize_tag("3teams")); |
41 | + add_tag_checkbox(&tags_box_, "4teams", localize_tag("4teams")); |
42 | |
43 | teams_box_.add(new UI::Textarea(&teams_box_, 0, 0, max_w_, labelh_, _("Suggested Teams:")), |
44 | UI::Align::kLeft); |
45 | |
46 | === modified file 'src/graphic/text/rt_parse.cc' |
47 | --- src/graphic/text/rt_parse.cc 2016-03-14 19:49:52 +0000 |
48 | +++ src/graphic/text/rt_parse.cc 2016-05-06 08:30:33 +0000 |
49 | @@ -274,6 +274,7 @@ |
50 | |
51 | tc.allowed_children.insert("br"); |
52 | tc.allowed_children.insert("space"); |
53 | + tc.allowed_children.insert("vspace"); |
54 | tc.allowed_children.insert("p"); |
55 | tc.allowed_children.insert("font"); |
56 | tc.allowed_children.insert("sub"); |
57 | |
58 | === modified file 'src/ui_basic/multilinetextarea.cc' |
59 | --- src/ui_basic/multilinetextarea.cc 2016-04-01 09:29:17 +0000 |
60 | +++ src/ui_basic/multilinetextarea.cc 2016-05-06 08:30:33 +0000 |
61 | @@ -41,7 +41,8 @@ |
62 | Panel (parent, x, y, w, h), |
63 | text_ (text), |
64 | color_(UI_FONT_CLR_FG), |
65 | - isrichtext(false), |
66 | + force_new_renderer_(false), |
67 | + use_old_renderer_(false), |
68 | scrollbar_ (this, get_w() - Scrollbar::kSize, 0, Scrollbar::kSize, h, false), |
69 | scrollmode_(scroll_mode) |
70 | { |
71 | @@ -56,14 +57,11 @@ |
72 | scrollbar_.set_singlestepsize(UI::g_fh1->render(as_uifont( |
73 | UI::g_fh1->fontset()->representative_character(), |
74 | UI_FONT_SIZE_SMALL))->height()); |
75 | - scrollbar_.set_pagesize(h - 2 * UI::g_fh1->render(as_uifont( |
76 | - UI::g_fh1->fontset()->representative_character(), |
77 | - UI_FONT_SIZE_BIG))->height()); |
78 | scrollbar_.set_steps(1); |
79 | scrollbar_.set_force_draw(scrollmode_ == ScrollMode::kScrollNormalForced || |
80 | scrollmode_ == ScrollMode::kScrollLogForced); |
81 | |
82 | - recompute(); |
83 | + layout(); |
84 | } |
85 | |
86 | |
87 | @@ -88,12 +86,16 @@ |
88 | // We wrap the text twice. We need to do this to account for the presence/absence of the scollbar. |
89 | bool scrollbar_was_enabled = scrollbar_.is_enabled(); |
90 | for (int i = 0; i < 2; ++i) { |
91 | - if (text_.compare(0, 3, "<rt")) { |
92 | - isrichtext = false; |
93 | + if (!is_richtext(text_)) { |
94 | + use_old_renderer_ = false; |
95 | const Image* text_im = UI::g_fh1->render(make_richtext(), get_eff_w() - 2 * RICHTEXT_MARGIN); |
96 | height = text_im->height(); |
97 | + } else if (force_new_renderer_) { |
98 | + use_old_renderer_ = false; |
99 | + const Image* text_im = UI::g_fh1->render(text_, get_eff_w() - 2 * RICHTEXT_MARGIN); |
100 | + height = text_im->height(); |
101 | } else { |
102 | - isrichtext = true; |
103 | + use_old_renderer_ = true; |
104 | rt.set_width(get_eff_w() - 2 * RICHTEXT_MARGIN); |
105 | rt.parse(text_); |
106 | height = rt.height() + 2 * RICHTEXT_MARGIN; |
107 | @@ -128,14 +130,15 @@ |
108 | { |
109 | } |
110 | |
111 | -/// Take care about scrollbar on resize |
112 | +/// Take care of the scrollbar on resize |
113 | void MultilineTextarea::layout() |
114 | { |
115 | recompute(); |
116 | |
117 | - // Take care about the scrollbar |
118 | + // Take care of the scrollbar |
119 | scrollbar_.set_pos(Point(get_w() - Scrollbar::kSize, 0)); |
120 | scrollbar_.set_size(Scrollbar::kSize, get_h()); |
121 | + scrollbar_.set_pagesize(get_h() - 2 * UI_FONT_SIZE_BIG); |
122 | } |
123 | |
124 | /** |
125 | @@ -143,10 +146,15 @@ |
126 | */ |
127 | void MultilineTextarea::draw(RenderTarget& dst) |
128 | { |
129 | - if (isrichtext) { |
130 | + if (use_old_renderer_) { |
131 | rt.draw(dst, Point(RICHTEXT_MARGIN, RICHTEXT_MARGIN - scrollbar_.get_scrollpos())); |
132 | } else { |
133 | - const Image* text_im = UI::g_fh1->render(make_richtext(), get_eff_w() - 2 * RICHTEXT_MARGIN); |
134 | + const Image* text_im; |
135 | + if (!is_richtext(text_)) { |
136 | + text_im = UI::g_fh1->render(make_richtext(), get_eff_w() - 2 * RICHTEXT_MARGIN); |
137 | + } else { |
138 | + text_im = UI::g_fh1->render(text_, get_eff_w() - 2 * RICHTEXT_MARGIN); |
139 | + } |
140 | |
141 | uint32_t blit_width = std::min(text_im->width(), static_cast<int>(get_eff_w())); |
142 | uint32_t blit_height = std::min(text_im->height(), static_cast<int>(get_inner_h())); |
143 | |
144 | === modified file 'src/ui_basic/multilinetextarea.h' |
145 | --- src/ui_basic/multilinetextarea.h 2016-04-01 12:22:09 +0000 |
146 | +++ src/ui_basic/multilinetextarea.h 2016-05-06 08:30:33 +0000 |
147 | @@ -58,6 +58,7 @@ |
148 | uint32_t get_eff_w() const {return scrollbar_.is_enabled() ? get_w() - Scrollbar::kSize : get_w();} |
149 | |
150 | void set_color(RGBColor fg) {color_ = fg;} |
151 | + void force_new_renderer() {force_new_renderer_ = true;} |
152 | |
153 | // Drawing and event handlers |
154 | void draw(RenderTarget&) override; |
155 | @@ -82,7 +83,8 @@ |
156 | RGBColor color_; |
157 | Align align_; |
158 | |
159 | - bool isrichtext; |
160 | + bool force_new_renderer_; |
161 | + bool use_old_renderer_; |
162 | RichText rt; |
163 | |
164 | Scrollbar scrollbar_; |
165 | |
166 | === modified file 'src/ui_basic/scrollbar.cc' |
167 | --- src/ui_basic/scrollbar.cc 2016-03-25 17:01:05 +0000 |
168 | +++ src/ui_basic/scrollbar.cc 2016-05-06 08:30:33 +0000 |
169 | @@ -85,6 +85,7 @@ |
170 | set_scrollpos(steps - 1); |
171 | |
172 | steps_ = steps; |
173 | + layout(); |
174 | } |
175 | |
176 | |
177 | @@ -111,6 +112,7 @@ |
178 | singlestepsize = 1; |
179 | |
180 | singlestepsize_ = singlestepsize; |
181 | + layout(); |
182 | } |
183 | |
184 | |
185 | @@ -120,6 +122,7 @@ |
186 | void Scrollbar::set_pagesize(int32_t const pagesize) |
187 | { |
188 | pagesize_ = pagesize < 1 ? 1 : pagesize; |
189 | + layout(); |
190 | } |
191 | |
192 | |
193 | |
194 | === modified file 'src/ui_fsmenu/launch_mpg.cc' |
195 | --- src/ui_fsmenu/launch_mpg.cc 2016-04-05 07:51:48 +0000 |
196 | +++ src/ui_fsmenu/launch_mpg.cc 2016-05-06 08:30:33 +0000 |
197 | @@ -234,7 +234,7 @@ |
198 | // Y coordinate will be set later, when we know how high this box will get. |
199 | suggested_teams_box_ = new UI::SuggestedTeamsBox |
200 | (this, right_column_x_, 0, UI::Box::Vertical, |
201 | - padding_, indent_, label_height_, |
202 | + padding_, indent_, |
203 | get_w() - right_column_x_, 4 * label_height_); |
204 | } |
205 | |
206 | |
207 | === modified file 'src/ui_fsmenu/mapselect.cc' |
208 | --- src/ui_fsmenu/mapselect.cc 2016-03-25 17:40:51 +0000 |
209 | +++ src/ui_fsmenu/mapselect.cc 2016-05-06 08:30:33 +0000 |
210 | @@ -31,6 +31,7 @@ |
211 | #include "logic/game_controller.h" |
212 | #include "logic/game_settings.h" |
213 | #include "map_io/widelands_map_loader.h" |
214 | +#include "wui/map_tags.h" |
215 | |
216 | // TODO(GunChleoc): Arabic: line height broken for descriptions for Arabic. |
217 | // Fix align for table headings & entries and for wordwrap. |
218 | @@ -52,7 +53,7 @@ |
219 | table_(this, tablex_, tabley_, tablew_, tableh_, false), |
220 | map_details_(this, right_column_x_, tabley_, |
221 | get_right_column_w(right_column_x_), |
222 | - tableh_ - buth_ - 4 * padding_), |
223 | + tableh_ - buth_ - 4 * padding_, MapDetails::Style::kFsMenu), |
224 | |
225 | basedir_("maps"), |
226 | settings_(settings), |
227 | @@ -94,27 +95,27 @@ |
228 | vbox = new UI::Box(this, |
229 | tablex_, vbox->get_y() + vbox->get_h() + padding_, |
230 | UI::Box::Horizontal, checkbox_space_, get_w()); |
231 | - add_tag_checkbox(vbox, "official", _("Official")); |
232 | - add_tag_checkbox(vbox, "unbalanced", _("Unbalanced")); |
233 | - add_tag_checkbox(vbox, "seafaring", _("Seafaring")); |
234 | - add_tag_checkbox(vbox, "artifacts", _("Artifacts")); |
235 | - add_tag_checkbox(vbox, "scenario", _("Scenario")); |
236 | - vbox->set_size(get_w() - 2 * tablex_, checkbox_space_); |
237 | - |
238 | - vbox = new UI::Box(this, |
239 | - tablex_, vbox->get_y() + vbox->get_h() + padding_, |
240 | - UI::Box::Horizontal, checkbox_space_, get_w()); |
241 | - add_tag_checkbox(vbox, "ffa", _("Free for all")); |
242 | - add_tag_checkbox(vbox, "1v1", _("1v1")); |
243 | - |
244 | - vbox->set_size(get_w() - 2 * tablex_, checkbox_space_); |
245 | - |
246 | - vbox = new UI::Box(this, |
247 | - tablex_, vbox->get_y() + vbox->get_h() + padding_, |
248 | - UI::Box::Horizontal, checkbox_space_, get_w()); |
249 | - add_tag_checkbox(vbox, "2teams", _("Teams of 2")); |
250 | - add_tag_checkbox(vbox, "3teams", _("Teams of 3")); |
251 | - add_tag_checkbox(vbox, "4teams", _("Teams of 4")); |
252 | + add_tag_checkbox(vbox, "official", localize_tag("official")); |
253 | + add_tag_checkbox(vbox, "unbalanced", localize_tag("unbalanced")); |
254 | + add_tag_checkbox(vbox, "seafaring", localize_tag("seafaring")); |
255 | + add_tag_checkbox(vbox, "artifacts", localize_tag("artifacts")); |
256 | + add_tag_checkbox(vbox, "scenario", localize_tag("scenario")); |
257 | + vbox->set_size(get_w() - 2 * tablex_, checkbox_space_); |
258 | + |
259 | + vbox = new UI::Box(this, |
260 | + tablex_, vbox->get_y() + vbox->get_h() + padding_, |
261 | + UI::Box::Horizontal, checkbox_space_, get_w()); |
262 | + add_tag_checkbox(vbox, "ffa", localize_tag("ffa")); |
263 | + add_tag_checkbox(vbox, "1v1", localize_tag("1v1")); |
264 | + |
265 | + vbox->set_size(get_w() - 2 * tablex_, checkbox_space_); |
266 | + |
267 | + vbox = new UI::Box(this, |
268 | + tablex_, vbox->get_y() + vbox->get_h() + padding_, |
269 | + UI::Box::Horizontal, checkbox_space_, get_w()); |
270 | + add_tag_checkbox(vbox, "2teams", localize_tag("2teams")); |
271 | + add_tag_checkbox(vbox, "3teams", localize_tag("3teams")); |
272 | + add_tag_checkbox(vbox, "4teams", localize_tag("4teams")); |
273 | vbox->set_size(get_w() - 2 * tablex_, checkbox_space_); |
274 | |
275 | scenario_types_ = settings_->settings().multiplayer ? Map::MP_SCENARIO : Map::SP_SCENARIO; |
276 | |
277 | === modified file 'src/wui/CMakeLists.txt' |
278 | --- src/wui/CMakeLists.txt 2016-04-02 16:45:53 +0000 |
279 | +++ src/wui/CMakeLists.txt 2016-05-06 08:30:33 +0000 |
280 | @@ -63,6 +63,8 @@ |
281 | mapdata.h |
282 | maptable.cc |
283 | maptable.h |
284 | + map_tags.cc |
285 | + map_tags.h |
286 | suggested_teams_box.cc |
287 | suggested_teams_box.h |
288 | DEPENDS |
289 | |
290 | === added file 'src/wui/map_tags.cc' |
291 | --- src/wui/map_tags.cc 1970-01-01 00:00:00 +0000 |
292 | +++ src/wui/map_tags.cc 2016-05-06 08:30:33 +0000 |
293 | @@ -0,0 +1,60 @@ |
294 | +/* |
295 | + * Copyright (C) 2016 by the Widelands Development Team |
296 | + * |
297 | + * This program is free software; you can redistribute it and/or |
298 | + * modify it under the terms of the GNU General Public License |
299 | + * as published by the Free Software Foundation; either version 2 |
300 | + * of the License, or (at your option) any later version. |
301 | + * |
302 | + * This program is distributed in the hope that it will be useful, |
303 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
304 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
305 | + * GNU General Public License for more details. |
306 | + * |
307 | + * You should have received a copy of the GNU General Public License |
308 | + * along with this program; if not, write to the Free Software |
309 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
310 | + * |
311 | + */ |
312 | + |
313 | +#include "wui/map_tags.h" |
314 | + |
315 | +#include "base/i18n.h" |
316 | + |
317 | +namespace { |
318 | + |
319 | +const std::map<std::string, std::string> kMapTags = { |
320 | + /** TRANSLATORS: This is a map tag */ |
321 | + {"official", _("Official")}, |
322 | + /** TRANSLATORS: This is a map tag */ |
323 | + {"unbalanced", _("Unbalanced")}, |
324 | + /** TRANSLATORS: This is a map tag */ |
325 | + {"seafaring", _("Seafaring")}, |
326 | + /** TRANSLATORS: This is a map tag */ |
327 | + {"artifacts", _("Artifacts")}, |
328 | + /** TRANSLATORS: This is a map tag */ |
329 | + {"scenario", _("Scenario")}, |
330 | + /** TRANSLATORS: This is a map tag */ |
331 | + {"ffa", _("Free for all")}, |
332 | + /** TRANSLATORS: This is a map tag. One versus one. */ |
333 | + {"1v1", _("1v1")}, |
334 | + /** TRANSLATORS: This is a map tag */ |
335 | + {"2teams", _("Teams of 2")}, |
336 | + /** TRANSLATORS: This is a map tag */ |
337 | + {"3teams", _("Teams of 3")}, |
338 | + /** TRANSLATORS: This is a map tag */ |
339 | + {"4teams", _("Teams of 4")}, |
340 | +}; |
341 | + |
342 | +} // namespace |
343 | + |
344 | +bool tag_exists(const std::string& tag) { |
345 | + return kMapTags.count(tag) == 1; |
346 | +} |
347 | + |
348 | +const std::string localize_tag(const std::string& tag) { |
349 | + if (tag_exists(tag)) { |
350 | + return _((*kMapTags.find(tag)).second); |
351 | + } |
352 | + return tag; |
353 | +} |
354 | |
355 | === added file 'src/wui/map_tags.h' |
356 | --- src/wui/map_tags.h 1970-01-01 00:00:00 +0000 |
357 | +++ src/wui/map_tags.h 2016-05-06 08:30:33 +0000 |
358 | @@ -0,0 +1,35 @@ |
359 | +/* |
360 | + * Copyright (C) 2016 by the Widelands Development Team |
361 | + * |
362 | + * This program is free software; you can redistribute it and/or |
363 | + * modify it under the terms of the GNU General Public License |
364 | + * as published by the Free Software Foundation; either version 2 |
365 | + * of the License, or (at your option) any later version. |
366 | + * |
367 | + * This program is distributed in the hope that it will be useful, |
368 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
369 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
370 | + * GNU General Public License for more details. |
371 | + * |
372 | + * You should have received a copy of the GNU General Public License |
373 | + * along with this program; if not, write to the Free Software |
374 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
375 | + * |
376 | + */ |
377 | + |
378 | +#ifndef WL_WUI_MAP_TAGS_H |
379 | +#define WL_WUI_MAP_TAGS_H |
380 | + |
381 | +#include <map> |
382 | +#include <string> |
383 | + |
384 | +/// Functions for localizing the known map tags. |
385 | + |
386 | +/// Returns true if this tag is known. |
387 | +bool tag_exists(const std::string& tag); |
388 | + |
389 | +/// If tag_exists, returns the localized tag. |
390 | +/// Otherwise, returns 'tag' |
391 | +const std::string localize_tag(const std::string& tag); |
392 | + |
393 | +#endif // end of include guard: WL_WUI_MAP_TAGS_H |
394 | |
395 | === modified file 'src/wui/mapdata.cc' |
396 | --- src/wui/mapdata.cc 2016-04-03 13:00:14 +0000 |
397 | +++ src/wui/mapdata.cc 2016-05-06 08:30:33 +0000 |
398 | @@ -30,10 +30,11 @@ |
399 | MapData() { |
400 | i18n::Textdomain td("maps"); |
401 | filename = init_filename; |
402 | - name = map.get_name(); |
403 | - localized_name = name.empty() ? "" : _(name); |
404 | + name = map.get_name().empty() ? _("No Name") : map.get_name(); |
405 | + localized_name = _(name); |
406 | // Localizing this, because some author fields now have "edited by" text. |
407 | - authors = MapAuthorData(_(map.get_author())); |
408 | + const std::string& author = map.get_author(); |
409 | + authors = MapAuthorData(author.empty() ? _("No Author") : _(author)); |
410 | description = map.get_description().empty() ? "" : _(map.get_description()); |
411 | hint = map.get_hint().empty() ? "" : _(map.get_hint()); |
412 | nrplayers = map.get_nrplayers(); |
413 | |
414 | === modified file 'src/wui/mapdetails.cc' |
415 | --- src/wui/mapdetails.cc 2016-04-01 18:05:40 +0000 |
416 | +++ src/wui/mapdetails.cc 2016-05-06 08:30:33 +0000 |
417 | @@ -1,5 +1,5 @@ |
418 | /* |
419 | - * Copyright (C) 2002, 2006-2015 by the Widelands Development Team |
420 | + * Copyright (C) 2002-2016 by the Widelands Development Team |
421 | * |
422 | * This program is free software; you can redistribute it and/or |
423 | * modify it under the terms of the GNU General Public License |
424 | @@ -18,6 +18,7 @@ |
425 | |
426 | #include "wui/mapdetails.h" |
427 | |
428 | +#include <algorithm> |
429 | #include <cstdio> |
430 | #include <memory> |
431 | |
432 | @@ -33,74 +34,72 @@ |
433 | #include "logic/game_settings.h" |
434 | #include "map_io/widelands_map_loader.h" |
435 | #include "ui_basic/box.h" |
436 | +#include "wui/map_tags.h" |
437 | + |
438 | +namespace { |
439 | +std::string as_header(const std::string& txt, MapDetails::Style style, bool is_first = false) { |
440 | + switch (style) { |
441 | + case MapDetails::Style::kFsMenu: |
442 | + return (boost::format("<p><font size=%i bold=1 shadow=1>%s%s</font></p>") |
443 | + % UI_FONT_SIZE_SMALL |
444 | + % (is_first ? "" : "<vspace gap=9>") |
445 | + % richtext_escape(txt)).str(); |
446 | + case MapDetails::Style::kWui: |
447 | + return (boost::format("<p><font size=%i bold=1 color=D1D1D1>%s%s</font></p>") |
448 | + % UI_FONT_SIZE_SMALL |
449 | + % (is_first ? "" : "<vspace gap=6>") |
450 | + % richtext_escape(txt)).str(); |
451 | + default: |
452 | + NEVER_HERE(); |
453 | + } |
454 | +} |
455 | +std::string as_content(const std::string& txt, MapDetails::Style style) { |
456 | + switch (style) { |
457 | + case MapDetails::Style::kFsMenu: |
458 | + return (boost::format("<p><font size=%i bold=1 color=D1D1D1 shadow=1><vspace gap=2>%s</font></p>") |
459 | + % UI_FONT_SIZE_SMALL |
460 | + % richtext_escape(txt)).str(); |
461 | + case MapDetails::Style::kWui: |
462 | + return (boost::format("<p><font size=%i><vspace gap=2>%s</font></p>") |
463 | + % (UI_FONT_SIZE_SMALL - 2) |
464 | + % richtext_escape(txt)).str(); |
465 | + default: |
466 | + NEVER_HERE(); |
467 | + } |
468 | +} |
469 | +} // namespace |
470 | |
471 | MapDetails::MapDetails |
472 | - (Panel* parent, int32_t x, int32_t y, int32_t max_x, int32_t max_y) : |
473 | - UI::Panel(parent, x, y, max_x, max_y), |
474 | + (Panel* parent, int32_t x, int32_t y, int32_t max_w, int32_t max_h, Style style) : |
475 | + UI::Panel(parent, x, y, max_w, max_h), |
476 | |
477 | + style_(style), |
478 | padding_(4), |
479 | - indent_(10), |
480 | - labelh_(20), |
481 | - max_w_(max_x), |
482 | - max_h_(max_y), |
483 | - // Subtract for main box and author box |
484 | - descr_box_height_(max_y - 4 * labelh_ - 5 * padding_), |
485 | - |
486 | - main_box_(this, 0, 0, UI::Box::Vertical, |
487 | - max_w_, max_h_, 0), |
488 | - |
489 | - name_box_(&main_box_, 0, 0, UI::Box::Horizontal, |
490 | - max_w_, 3 * labelh_ + padding_, padding_ / 2), |
491 | - name_label_(&main_box_, 0, 0, max_w_ - padding_, labelh_, ""), |
492 | - name_(&name_box_, 0, 0, max_w_ - indent_, 2 * labelh_, ""), |
493 | - |
494 | - author_box_(&main_box_, 0, 0, UI::Box::Horizontal, |
495 | - max_w_, 3 * labelh_ + padding_, padding_ / 2), |
496 | - author_label_(&main_box_, 0, 0, max_w_ - padding_, labelh_, ""), |
497 | - author_(&author_box_, 0, 0, max_w_ - indent_, labelh_, ""), |
498 | - |
499 | - descr_box_(&main_box_, 0, 0, UI::Box::Horizontal, |
500 | - max_w_, descr_box_height_, padding_ / 2), |
501 | - descr_label_(&main_box_, 0, 0, max_w_, labelh_, ""), |
502 | - // -1 to prevent cropping of scrollbar |
503 | - descr_(&descr_box_, 0, 0, max_w_ - indent_ - 1, descr_box_height_ - labelh_ - padding_, "") |
504 | + main_box_(this, 0, 0, UI::Box::Vertical, max_w, max_h, 0), |
505 | + name_label_(&main_box_, 0, 0, max_w - padding_, 20, "", UI::Align::kLeft, |
506 | + UI::MultilineTextarea::ScrollMode::kNoScrolling), |
507 | + descr_(&main_box_, 0, 0, max_w, 20, ""), |
508 | + suggested_teams_box_(new UI::SuggestedTeamsBox(this, 0, 0, UI::Box::Vertical, padding_, 0, max_w)) |
509 | { |
510 | - suggested_teams_box_ = new UI::SuggestedTeamsBox(this, 0, 0, UI::Box::Vertical, |
511 | - padding_, indent_, labelh_, max_w_, 4 * labelh_); |
512 | + name_label_.force_new_renderer(); |
513 | + descr_.force_new_renderer(); |
514 | |
515 | main_box_.add(&name_label_, UI::Align::kLeft); |
516 | - name_box_.add_space(indent_); |
517 | - name_box_.add(&name_, UI::Align::kLeft); |
518 | - main_box_.add(&name_box_, UI::Align::kLeft); |
519 | - main_box_.add_space(padding_); |
520 | - |
521 | - main_box_.add(&author_label_, UI::Align::kLeft); |
522 | - author_box_.add_space(indent_); |
523 | - author_box_.add(&author_, UI::Align::kLeft); |
524 | - main_box_.add(&author_box_, UI::Align::kLeft); |
525 | - main_box_.add_space(padding_); |
526 | - |
527 | - main_box_.add(&descr_label_, UI::Align::kLeft); |
528 | - descr_box_.add_space(indent_); |
529 | - descr_box_.add(&descr_, UI::Align::kLeft); |
530 | - main_box_.add(&descr_box_, UI::Align::kLeft); |
531 | - main_box_.add_space(padding_); |
532 | + main_box_.add_space(padding_); |
533 | + main_box_.add(&descr_, UI::Align::kLeft); |
534 | + main_box_.set_size(max_w, max_h); // We need to initialize the width, set_max_height will set the height |
535 | + set_max_height(max_h); |
536 | } |
537 | |
538 | |
539 | void MapDetails::clear() { |
540 | name_label_.set_text(""); |
541 | - author_label_.set_text(""); |
542 | - descr_label_.set_text(""); |
543 | - name_.set_text(""); |
544 | - author_.set_text(""); |
545 | descr_.set_text(""); |
546 | suggested_teams_box_->hide(); |
547 | } |
548 | |
549 | void MapDetails::set_max_height(int new_height) { |
550 | max_h_ = new_height; |
551 | - descr_box_height_ = max_h_ - 4 * labelh_ - 5 * padding_; |
552 | update_layout(); |
553 | } |
554 | |
555 | @@ -108,58 +107,75 @@ |
556 | // Adjust sizes for show / hide suggested teams |
557 | if (suggested_teams_box_->is_visible()) { |
558 | suggested_teams_box_->set_pos(Point(0, max_h_ - suggested_teams_box_->get_h())); |
559 | - main_box_.set_size(max_w_, max_h_ - suggested_teams_box_->get_h()); |
560 | - descr_box_.set_size( |
561 | - descr_box_.get_w(), |
562 | - descr_box_height_ - suggested_teams_box_->get_h() - padding_); |
563 | + main_box_.set_size(main_box_.get_w(), max_h_ - suggested_teams_box_->get_h() - padding_); |
564 | } else { |
565 | - main_box_.set_size(max_w_, max_h_); |
566 | - descr_box_.set_size(descr_box_.get_w(), descr_box_height_); |
567 | + main_box_.set_size(main_box_.get_w(), max_h_); |
568 | } |
569 | - descr_.set_size(descr_.get_w(), descr_box_.get_h() - descr_label_.get_h() - padding_); |
570 | + descr_.set_size(descr_.get_w(), main_box_.get_h() - name_label_.get_h() - padding_); |
571 | descr_.scroll_to_top(); |
572 | } |
573 | |
574 | void MapDetails::update(const MapData& mapdata, bool localize_mapname) { |
575 | clear(); |
576 | + // Show directory information |
577 | if (mapdata.maptype == MapData::MapType::kDirectory) { |
578 | - // Show directory information |
579 | - name_label_.set_text(_("Directory:")); |
580 | - name_.set_text(mapdata.localized_name); |
581 | - name_.set_tooltip(_("The name of this directory")); |
582 | - main_box_.set_size(max_w_, max_h_); |
583 | - } else { |
584 | - // Show map information |
585 | - if (mapdata.maptype == MapData::MapType::kScenario) { |
586 | - name_label_.set_text(_("Scenario:")); |
587 | - } else { |
588 | - name_label_.set_text(_("Map:")); |
589 | - } |
590 | - name_.set_text(localize_mapname ? mapdata.localized_name : mapdata.name); |
591 | + name_label_.set_text((boost::format("<rt>%s%s</rt>") |
592 | + % as_header(_("Directory:"), style_, true) |
593 | + % as_content(mapdata.localized_name, style_)).str()); |
594 | + main_box_.set_size(main_box_.get_w(), max_h_); |
595 | + |
596 | + } else { // Show map information |
597 | + name_label_.set_text( |
598 | + (boost::format("<rt>%s%s</rt>") |
599 | + % as_header(mapdata.maptype == MapData::MapType::kScenario ? |
600 | + _("Scenario:") : _("Map:"), style_, true) |
601 | + % as_content(localize_mapname ? mapdata.localized_name : mapdata.name, style_)).str()); |
602 | + |
603 | if (mapdata.localized_name != mapdata.name) { |
604 | if (localize_mapname) { |
605 | - name_.set_tooltip |
606 | + name_label_.set_tooltip |
607 | /** TRANSLATORS: Tooltip in map description when translated map names are being displayed. */ |
608 | /** TRANSLATORS: %s is the English name of the map. */ |
609 | ((boost::format(_("The original name of this map: %s")) |
610 | % mapdata.name).str()); |
611 | } else { |
612 | - name_.set_tooltip |
613 | + name_label_.set_tooltip |
614 | /** TRANSLATORS: Tooltip in map description when map names are being displayed in English. */ |
615 | /** TRANSLATORS: %s is the localized name of the map. */ |
616 | ((boost::format(_("The name of this map in your language: %s")) |
617 | % mapdata.localized_name).str()); |
618 | } |
619 | - } else { |
620 | - name_.set_tooltip(_("The name of this map")); |
621 | - } |
622 | - author_label_.set_text(ngettext("Author:", "Authors:", mapdata.authors.get_number())); |
623 | - author_.set_text(mapdata.authors.get_names()); |
624 | - descr_label_.set_text(_("Description:")); |
625 | - descr_.set_text( |
626 | - mapdata.description + |
627 | - /** TRANSLATORS: Map hint header when selecting a map. */ |
628 | - (mapdata.hint.empty() ? "" : (std::string("\n\n") + _("HINT:") + "\n" + mapdata.hint))); |
629 | + } |
630 | + |
631 | + // Show map information |
632 | + std::string description = |
633 | + as_header(ngettext("Author:", "Authors:", mapdata.authors.get_number()), style_); |
634 | + description = (boost::format("%s%s") |
635 | + % description |
636 | + % as_content(mapdata.authors.get_names(), style_)).str(); |
637 | + |
638 | + std::vector<std::string> tags; |
639 | + for (const auto& tag : mapdata.tags) { |
640 | + tags.push_back(localize_tag(tag)); |
641 | + } |
642 | + std::sort(tags.begin(), tags.end()); |
643 | + description = (boost::format("%s%s") % description % as_header(_("Tags:"), style_)).str(); |
644 | + description = (boost::format("%s%s") |
645 | + % description % |
646 | + as_content(i18n::localize_list(tags, i18n::ConcatenateWith::COMMA), style_)) |
647 | + .str(); |
648 | + |
649 | + description = (boost::format("%s%s") % description % as_header(_("Description:"), style_)).str(); |
650 | + description = (boost::format("%s%s") % description % as_content(mapdata.description, style_)).str(); |
651 | + |
652 | + if (!mapdata.hint.empty()) { |
653 | + /** TRANSLATORS: Map hint header when selecting a map. */ |
654 | + description = (boost::format("%s%s") % description % as_header(_("Hint:"), style_)).str(); |
655 | + description = (boost::format("%s%s") % description % as_content(mapdata.hint, style_)).str(); |
656 | + } |
657 | + |
658 | + description = (boost::format("<rt>%s</rt>") % description).str(); |
659 | + descr_.set_text(description); |
660 | |
661 | // Show / hide suggested teams |
662 | if (mapdata.suggested_teams.empty()) { |
663 | |
664 | === modified file 'src/wui/mapdetails.h' |
665 | --- src/wui/mapdetails.h 2016-03-23 08:47:27 +0000 |
666 | +++ src/wui/mapdetails.h 2016-05-06 08:30:33 +0000 |
667 | @@ -23,7 +23,6 @@ |
668 | #include "ui_basic/box.h" |
669 | #include "ui_basic/multilinetextarea.h" |
670 | #include "ui_basic/panel.h" |
671 | -#include "ui_basic/textarea.h" |
672 | #include "wui/mapdata.h" |
673 | #include "wui/suggested_teams_box.h" |
674 | |
675 | @@ -33,9 +32,12 @@ |
676 | */ |
677 | class MapDetails : public UI::Panel { |
678 | public: |
679 | - MapDetails(Panel * parent, |
680 | - int32_t x, int32_t y, |
681 | - int32_t max_x, int32_t max_y); |
682 | + enum class Style { |
683 | + kFsMenu, |
684 | + kWui |
685 | + }; |
686 | + |
687 | + MapDetails(Panel* parent, int32_t x, int32_t y, int32_t max_w, int32_t max_h, Style style); |
688 | |
689 | void clear(); |
690 | void set_max_height(int new_height); |
691 | @@ -43,23 +45,13 @@ |
692 | void update(const MapData& mapdata, bool localize_mapname); |
693 | |
694 | private: |
695 | - const int padding_, indent_, labelh_, max_w_; |
696 | - int max_h_, descr_box_height_; |
697 | + const Style style_; |
698 | + const int padding_; |
699 | + int max_h_; |
700 | |
701 | UI::Box main_box_; |
702 | - |
703 | - UI::Box name_box_; |
704 | - UI::Textarea name_label_; |
705 | - UI::MultilineTextarea name_; |
706 | - |
707 | - UI::Box author_box_; |
708 | - UI::Textarea author_label_; |
709 | - UI::MultilineTextarea author_; |
710 | - |
711 | - UI::Box descr_box_; |
712 | - UI::Textarea descr_label_; |
713 | + UI::MultilineTextarea name_label_; |
714 | UI::MultilineTextarea descr_; |
715 | - |
716 | UI::SuggestedTeamsBox* suggested_teams_box_; |
717 | }; |
718 | |
719 | |
720 | === modified file 'src/wui/suggested_teams_box.cc' |
721 | --- src/wui/suggested_teams_box.cc 2016-02-10 20:39:02 +0000 |
722 | +++ src/wui/suggested_teams_box.cc 2016-05-06 08:30:33 +0000 |
723 | @@ -42,13 +42,12 @@ |
724 | SuggestedTeamsBox::SuggestedTeamsBox(Panel * parent, |
725 | int32_t x, int32_t y, |
726 | uint32_t orientation, |
727 | - int32_t padding, int32_t indent, int32_t label_height, |
728 | - int32_t max_x, int32_t max_y, |
729 | - uint32_t inner_spacing) : |
730 | - UI::Box(parent, x, y, orientation, max_x, max_y, inner_spacing), |
731 | + int32_t padding, int32_t indent, |
732 | + int32_t max_x, int32_t max_y) : |
733 | + UI::Box(parent, x, y, orientation, max_x, max_y, g_gr->images().get(player_pictures_small[0])->height()), |
734 | padding_(padding), |
735 | indent_(indent), |
736 | - label_height_(label_height) |
737 | + label_height_(g_gr->images().get(player_pictures_small[0])->height() + padding) |
738 | { |
739 | player_icons_.clear(); |
740 | suggested_teams_.clear(); |
741 | @@ -105,10 +104,10 @@ |
742 | for (const Widelands::Map::SuggestedTeamLineup& lineup : suggested_teams_) { |
743 | |
744 | lineup_box_ = |
745 | - new UI::Box(this, indent_, teamlist_offset + lineup_counter * (label_height_ + padding_), |
746 | + new UI::Box(this, indent_, teamlist_offset + lineup_counter * (label_height_), |
747 | UI::Box::Horizontal, get_w() - indent_); |
748 | |
749 | - lineup_box_->set_size(get_w(), label_height_ + padding_); |
750 | + lineup_box_->set_size(get_w(), label_height_); |
751 | |
752 | bool is_first = true; |
753 | for (const Widelands::Map::SuggestedTeam& team : lineup) { |
754 | @@ -127,7 +126,8 @@ |
755 | assert(player < MAX_PLAYERS); |
756 | const Image* player_image = g_gr->images().get(player_pictures_small[player]); |
757 | assert(player_image); |
758 | - player_icon = new UI::Icon(lineup_box_, 0, 0, 20, 20, player_image); |
759 | + player_icon = new UI::Icon(lineup_box_, 0, 0, |
760 | + player_image->width(), player_image->height(), player_image); |
761 | player_icon->set_visible(true); |
762 | player_icon->set_no_frame(); |
763 | lineup_box_->add(player_icon, UI::Align::kLeft); |
764 | @@ -138,7 +138,7 @@ |
765 | } // All lineups |
766 | |
767 | // Adjust size to content |
768 | - set_size(get_w(), teamlist_offset + lineup_counter * (label_height_ + padding_)); |
769 | + set_size(get_w(), teamlist_offset + lineup_counter * (label_height_)); |
770 | } |
771 | } |
772 | |
773 | |
774 | === modified file 'src/wui/suggested_teams_box.h' |
775 | --- src/wui/suggested_teams_box.h 2016-01-24 20:11:53 +0000 |
776 | +++ src/wui/suggested_teams_box.h 2016-05-06 08:30:33 +0000 |
777 | @@ -36,9 +36,8 @@ |
778 | SuggestedTeamsBox(Panel * parent, |
779 | int32_t x, int32_t y, |
780 | uint32_t orientation, |
781 | - int32_t padding, int32_t indent, int32_t label_height, |
782 | - int32_t max_x = 0, int32_t max_y = 0, |
783 | - uint32_t inner_spacing = 0); |
784 | + int32_t padding, int32_t indent, |
785 | + int32_t max_x = 0, int32_t max_y = 0); |
786 | ~SuggestedTeamsBox(); |
787 | |
788 | void hide(); |
Good ideas :-)
Some things:
1. The slider of the scrollbar does not change his size if there is less to scroll (the slider is always small) Good to see in screen resolution 1280x720 and map Four Mountains.
2. There are obsolete information: "Map size" and "2/3/4/... Player map". These information is always in the table, so why should we have it in the description again?
3. Having non bold text for normal descriptions is fine, but for me it is hard to read in the first time. Maybe we could have another color for the text or a different background?
Showing the tags is a good idea :-)
Just a side note:
For a longer time i thought of a rework of the menus (especially in regard to my point 3), but i had no good ideas until today... and of course i do not know which possibilities there are. F.e. the checkboxes in "New game" looks a bit unordered and i guess some of them aren't used at all. Maybe we could make a poll on the website to determine what is really needed here. But creating a good, useful ui is a long and not easy task ... So nothing against your work :-)