Merge lp:~widelands-dev/widelands/bug-536489-dropdown into lp:widelands

Proposed by GunChleoc
Status: Merged
Merged at revision: 8158
Proposed branch: lp:~widelands-dev/widelands/bug-536489-dropdown
Merge into: lp:widelands
Diff against target: 1660 lines (+726/-199)
23 files modified
src/editor/ui_menus/main_menu_map_options.cc (+1/-1)
src/ui_basic/CMakeLists.txt (+2/-0)
src/ui_basic/button.cc (+9/-3)
src/ui_basic/button.h (+1/-2)
src/ui_basic/checkbox.cc (+3/-1)
src/ui_basic/dropdown.cc (+215/-0)
src/ui_basic/dropdown.h (+166/-0)
src/ui_basic/listselect.cc (+85/-34)
src/ui_basic/listselect.h (+45/-8)
src/ui_basic/panel.cc (+1/-1)
src/ui_basic/panel.h (+1/-1)
src/ui_basic/progressbar.cc (+2/-2)
src/ui_basic/scrollbar.cc (+2/-1)
src/ui_basic/slider.cc (+4/-0)
src/ui_basic/tabpanel.cc (+10/-12)
src/ui_basic/window.cc (+17/-13)
src/ui_fsmenu/launch_mpg.cc (+1/-1)
src/ui_fsmenu/launch_spg.cc (+101/-63)
src/ui_fsmenu/launch_spg.h (+20/-6)
src/ui_fsmenu/mapselect.cc (+2/-1)
src/ui_fsmenu/options.cc (+34/-40)
src/ui_fsmenu/options.h (+3/-8)
src/wui/game_objectives_menu.cc (+1/-1)
To merge this branch: bzr merge lp:~widelands-dev/widelands/bug-536489-dropdown
Reviewer Review Type Date Requested Status
SirVer Approve
GunChleoc Needs Resubmitting
kaputtnik (community) testing Approve
Klaus Halfmann compile, test Approve
Review via email: mp+306303@code.launchpad.net

Commit message

Implemented a textual dropdown menu. It is used in:
- Options: Screen resolution
- Options: Language. Got rid of the extra Language tab and moved it to the Interface tab.
- Launch Single Player Game: Win Condition

Description of the change

My first branch for Build 20 ;)

Implemented a textual dropdown menu. This is already quite a bit of code, so I'll do the win condition for multiplayer in a separate branch. We will also want pictorial dropdowns.

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

Continuous integration builds have changed state:

Travis build 1345. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/161548228.
Appveyor build 1187. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_536489_dropdown-1187.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

This Drodown is missing a feature found in all normal GUIs:

when you click outside the dropdown it will NOT collapse,
allowing the user to click somewhere else.
This implementation will do nothing in this case.
So if I forgot that the Dropdown is open and click somwhere else
It seems stuck as I get no visual feedback what to do.
This may frustrate players upto a level where theey will kill the game.

In additon it does not collapse when pressing Escape,
instead the complete dialog is canceled.

Sorry Gun.

Good work otherwise. I will continue to review the usage and code.

review: Needs Fixing (compile, test)
Revision history for this message
GunChleoc (gunchleoc) wrote :

Good points. The escape key thing should be easy to do, for the collapse when clicked outside of it I will need to dig around a bit.

Thanks for testing!

Revision history for this message
GunChleoc (gunchleoc) wrote :

Ready for the next round. It is now possible to navigate through the list with the keyboard as well.

Note: I forgot that Esc should cancel the change in the list, will still do that.

Handling a mouse click outside of a panel is tricky, so I autoclose if the mouse moves outside the panel. I gave this some distance so that the list won't disappear on users when they move the mouse 1 pixel off, let me know if we need to widen that. The tolerance is currently 50 pixels, and 25 for moving up.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1345. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/161548228.
Appveyor build 1187. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_536489_dropdown-1187.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Hello Gun,
thanks for your work.

* the Autoclose when leaving feels reasonbale. OK for me
* Esc-Key is handled as expected.

There is one confusion however:
The menu has a Selection - via a background color - and a checkmark.
When I use the cursor keys to scroll both, the selection and the
checkmark change. So I assume I made the choice. When I then leave
the list, I find that my selection was not applied (so the checkmark is wrong).

Please improve as follows: do not move the checkmark until the selection
in finally confirmed by clicking or by pressing return.

review: Needs Fixing (compile, test)
Revision history for this message
kaputtnik (franku) wrote :

I get a crash as soon i click on one of the dropdown menus in options:

src/ui_basic/panel.h:265: bool UI::Panel::has_focus() const: Assertion `get_can_focus()' failed.

Backtrace: https://bugs.launchpad.net/widelands/+bug/536489/+attachment/4750279/+files/backtrace.txt

review: Needs Fixing
Revision history for this message
GunChleoc (gunchleoc) wrote :

How would it be if there was no checkmark at all? Would that be confusing when the dropdown gets opens?

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

> How would it be if there was no checkmark at all?
> Would that be confusing when the dropdown gets opens?

Hm, the checkmark is a good and normal hint what the
current selection is. But you can completly drop it, in case
it is to diffult otherwise.

In the End you are our User-Interface Department.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Maybe I am, but your input is very helpful!

I just gave it a spin, I think it would be best if the mouse position / current selection gets highlighted, and no tick. Back to the drawing board :)

Revision history for this message
kaputtnik (franku) wrote :

Thanks for fixing the crash :-)

The checkmark is IMHO good now.

But clicking on the vertical slider in Options->Language let the drop down menu disappear.

review: Needs Fixing
Revision history for this message
GunChleoc (gunchleoc) wrote :

Collapse with the scrollbar should be fixed now. Also instant highlighting for mouse movement.

review: Needs Resubmitting
Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

last night I updated to OSX-Sierra

* The good news: Widelands starts (last status compiled form this branch)
* The bad one: When compiling it complains about some system headers.

I will open another Bug to collect this Issues, maybe I can fix them easily,

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

OK, fine for me, I did not take a deep look at that code, sorry.
As I can test macOS (Sierra) only, I would like to see Windows and Linux approvals, too

review: Approve (compile, test)
Revision history for this message
kaputtnik (franku) wrote :

One little thing: If the dropdown box is once opened and closed (with moving away the mouse pointer) and hitting the down arrow of the keyboard, the dropdownmenu sometimes pops up for little time. Best to see if you keep the down arrow down for a longer time.

Not really an issue, so i leave it up to you to fix this.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Good point - deactivated the key when the mouse is not on the dropdown.

Revision history for this message
kaputtnik (franku) wrote :

Great :-)

review: Approve (testing)
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1382. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/164389381.
Appveyor build 1224. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_536489_dropdown-1224.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1384. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/164458580.
Appveyor build 1226. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_536489_dropdown-1226.

Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

After merging the trunk I now get (in bzr8108[bug-536489-dropdown])

Spieldatenfehler
economies: player 3: Stream ended unexpectedly (0 bytes read, 4 expected)

So I was unable to continue playing my last save game.
As this happens in trunk to I will not complain more ...

Revision history for this message
GunChleoc (gunchleoc) wrote :

That error can't possibly be related to this branch, since you already said that it happens in trunk as well. It's worth reporting as a bug though.

Revision history for this message
SirVer (sirver) wrote :

Just tested under Mac OS. Really nice change. One possible eye candy nit/improvement could be a small line outside of the drop down at the bottom and the sides - to connect the drop down better with the original button.

I will review the code eventually.... no hurry here, build 19 is still a few weeks off.

Revision history for this message
kaputtnik (franku) wrote :

> One possible eye candy
> nit/improvement could be a small line outside of the drop down at the bottom
> and the sides - to connect the drop down better with the original button.

+1 (i thought something like this also)

Revision history for this message
GunChleoc (gunchleoc) wrote :

Beautification done :)

I also want to give the scrollbar some love, but I'll have to do that in a separate branch, since that will affect all kinds of stuff.

Revision history for this message
kaputtnik (franku) wrote :

Looks better now. Have you tested showing it flattened instead of raised?

Revision history for this message
GunChleoc (gunchleoc) wrote :

No, I think flattened is wrong for it - it is dropped down on top of the other elements, not below them.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1445. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/170387162.
Appveyor build 1288. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_536489_dropdown-1288.

Revision history for this message
SirVer (sirver) wrote :

A couple of change suggestions and questions in code

review: Needs Fixing
Revision history for this message
GunChleoc (gunchleoc) wrote :

Added some replies/questions.

Revision history for this message
SirVer (sirver) wrote :

you also need to merge trunk it seems.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1527. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/171318976.
Appveyor build 1288. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_536489_dropdown-1288.

Revision history for this message
GunChleoc (gunchleoc) wrote :

All fixed except for 1 comment - have added a comment on my own to the source code.

review: Needs Resubmitting
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 1531. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/171467686.
Appveyor build 1373. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_536489_dropdown-1373.

Revision history for this message
SirVer (sirver) wrote :

I added a inline comment there. Essentially, I still think it is worthwhile for clarity to pull this function out.

otherwise lgtm.

review: Approve
Revision history for this message
GunChleoc (gunchleoc) wrote :

You are right, it makes the function easier to read, so I've pulled it out.
Thanks for the review :)

@bunnybot merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/editor/ui_menus/main_menu_map_options.cc'
--- src/editor/ui_menus/main_menu_map_options.cc 2016-10-16 09:31:42 +0000
+++ src/editor/ui_menus/main_menu_map_options.cc 2016-10-29 10:23:37 +0000
@@ -79,7 +79,7 @@
79 author_(&main_box_, 0, 0, max_w_, 0, 2, g_gr->images().get("images/ui_basic/but1.png")),79 author_(&main_box_, 0, 0, max_w_, 0, 2, g_gr->images().get("images/ui_basic/but1.png")),
80 size_(&main_box_, 0, 0, max_w_ - indent_, labelh_, ""),80 size_(&main_box_, 0, 0, max_w_ - indent_, labelh_, ""),
8181
82 teams_list_(&teams_box_, 0, 0, max_w_, 60, true),82 teams_list_(&teams_box_, 0, 0, max_w_, 60, UI::ListselectLayout::kShowCheck),
8383
84 modal_(modal) {84 modal_(modal) {
8585
8686
=== modified file 'src/ui_basic/CMakeLists.txt'
--- src/ui_basic/CMakeLists.txt 2016-04-02 16:45:53 +0000
+++ src/ui_basic/CMakeLists.txt 2016-10-29 10:23:37 +0000
@@ -6,6 +6,8 @@
6 button.h6 button.h
7 checkbox.cc7 checkbox.cc
8 checkbox.h8 checkbox.h
9 dropdown.cc
10 dropdown.h
9 editbox.cc11 editbox.cc
10 editbox.h12 editbox.h
11 fileview_panel.cc13 fileview_panel.cc
1214
=== modified file 'src/ui_basic/button.cc'
--- src/ui_basic/button.cc 2016-10-24 14:04:00 +0000
+++ src/ui_basic/button.cc 2016-10-29 10:23:37 +0000
@@ -65,6 +65,7 @@
65 set_size(w, new_height);65 set_size(w, new_height);
66 }66 }
67 set_thinks(false);67 set_thinks(false);
68 set_can_focus(true);
68}69}
6970
70Button::Button // for pictorial buttons71Button::Button // for pictorial buttons
@@ -91,6 +92,7 @@
91 pic_custom_(fg_pic),92 pic_custom_(fg_pic),
92 clr_down_(229, 161, 2) {93 clr_down_(229, 161, 2) {
93 set_thinks(false);94 set_thinks(false);
95 set_can_focus(true);
94}96}
9597
96Button::~Button() {98Button::~Button() {
@@ -127,6 +129,8 @@
127 if (enabled_ == on)129 if (enabled_ == on)
128 return;130 return;
129131
132 set_can_focus(on);
133
130 // disabled buttons should look different...134 // disabled buttons should look different...
131 if (on)135 if (on)
132 enabled_ = true;136 enabled_ = true;
@@ -148,7 +152,8 @@
148 // Draw the background152 // Draw the background
149 if (pic_background_) {153 if (pic_background_) {
150 dst.fill_rect(Rectf(0.f, 0.f, get_w(), get_h()), RGBAColor(0, 0, 0, 255));154 dst.fill_rect(Rectf(0.f, 0.f, get_w(), get_h()), RGBAColor(0, 0, 0, 255));
151 dst.tile(Recti(Vector2i(0, 0), get_w(), get_h()), pic_background_, Vector2i(get_x(), get_y()));155 dst.tile(
156 Recti(Vector2i(0, 0), get_w(), get_h()), pic_background_, Vector2i(get_x(), get_y()));
152 }157 }
153158
154 if (enabled_ && highlighted_ && style_ != Style::kFlat)159 if (enabled_ && highlighted_ && style_ != Style::kFlat)
@@ -198,8 +203,8 @@
198 enabled_ ? UI_FONT_CLR_FG : UI_FONT_CLR_DISABLED);203 enabled_ ? UI_FONT_CLR_FG : UI_FONT_CLR_DISABLED);
199 // Blit on pixel boundary (not float), so that the text is blitted pixel perfect.204 // Blit on pixel boundary (not float), so that the text is blitted pixel perfect.
200 dst.blit(205 dst.blit(
201 Vector2f((get_w() - entry_text_im->width()) / 2, (get_h() - entry_text_im->height()) / 2),206 Vector2f((get_w() - entry_text_im->width()) / 2, (get_h() - entry_text_im->height()) / 2),
202 entry_text_im);207 entry_text_im);
203 }208 }
204209
205 // draw border210 // draw border
@@ -294,6 +299,7 @@
294 return false;299 return false;
295300
296 if (enabled_) {301 if (enabled_) {
302 focus();
297 grab_mouse(true);303 grab_mouse(true);
298 pressed_ = true;304 pressed_ = true;
299 if (repeating_) {305 if (repeating_) {
300306
=== modified file 'src/ui_basic/button.h'
--- src/ui_basic/button.h 2016-09-25 13:07:06 +0000
+++ src/ui_basic/button.h 2016-10-29 10:23:37 +0000
@@ -39,7 +39,7 @@
39 enum class Style {39 enum class Style {
40 kRaised, // Normal raised Button40 kRaised, // Normal raised Button
41 kPermpressed, // Button will appear pressed41 kPermpressed, // Button will appear pressed
42 kFlat // Flat button with simple coloured outline42 kFlat // Flat button with simple coloured outline
43 };43 };
4444
45 enum class ImageMode {45 enum class ImageMode {
@@ -108,7 +108,6 @@
108 /// Convenience function. If 'pressed', sets the style to kPermpressed, otherwise to kRaised.108 /// Convenience function. If 'pressed', sets the style to kPermpressed, otherwise to kRaised.
109 void set_perm_pressed(bool pressed);109 void set_perm_pressed(bool pressed);
110110
111
112 /// Convenience function. Toggles between raised and permpressed style111 /// Convenience function. Toggles between raised and permpressed style
113 void toggle();112 void toggle();
114113
115114
=== modified file 'src/ui_basic/checkbox.cc'
--- src/ui_basic/checkbox.cc 2016-10-16 20:35:47 +0000
+++ src/ui_basic/checkbox.cc 2016-10-29 10:23:37 +0000
@@ -43,7 +43,7 @@
43 uint16_t h = pic->height();43 uint16_t h = pic->height();
44 set_desired_size(w, h);44 set_desired_size(w, h);
45 set_size(w, h);45 set_size(w, h);
4646 set_can_focus(true);
47 set_flags(Has_Custom_Picture, true);47 set_flags(Has_Custom_Picture, true);
48 pic_graphics_ = pic;48 pic_graphics_ = pic;
49}49}
@@ -79,6 +79,7 @@
79 * Args: enabled true if the checkbox should be enabled, false otherwise79 * Args: enabled true if the checkbox should be enabled, false otherwise
80 */80 */
81void Statebox::set_enabled(bool const enabled) {81void Statebox::set_enabled(bool const enabled) {
82 set_can_focus(enabled);
82 if (((flags_ & Is_Enabled) > 1) && enabled)83 if (((flags_ & Is_Enabled) > 1) && enabled)
83 return;84 return;
8485
@@ -157,6 +158,7 @@
157 */158 */
158bool Statebox::handle_mousepress(const uint8_t btn, int32_t, int32_t) {159bool Statebox::handle_mousepress(const uint8_t btn, int32_t, int32_t) {
159 if (btn == SDL_BUTTON_LEFT && (flags_ & Is_Enabled)) {160 if (btn == SDL_BUTTON_LEFT && (flags_ & Is_Enabled)) {
161 focus();
160 clicked();162 clicked();
161 return true;163 return true;
162 }164 }
163165
=== added file 'src/ui_basic/dropdown.cc'
--- src/ui_basic/dropdown.cc 1970-01-01 00:00:00 +0000
+++ src/ui_basic/dropdown.cc 2016-10-29 10:23:37 +0000
@@ -0,0 +1,215 @@
1/*
2 * Copyright (C) 2016 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#include "ui_basic/dropdown.h"
21
22#include <algorithm>
23
24#include <boost/format.hpp>
25
26#include "base/i18n.h"
27#include "graphic/align.h"
28#include "graphic/font_handler1.h"
29#include "graphic/graphic.h"
30#include "graphic/image.h"
31#include "graphic/rendertarget.h"
32#include "ui_basic/mouse_constants.h"
33
34namespace UI {
35
36BaseDropdown::BaseDropdown(
37 UI::Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, const std::string& label)
38 : UI::Panel(
39 parent,
40 x,
41 y,
42 w,
43 std::max(24,
44 UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))
45 ->height() +
46 2)), // Height only to fit the button, so we can use this in Box layout.
47 max_list_height_(h - 2 * get_h()),
48 mouse_tolerance_(50),
49 button_box_(this, 0, 0, UI::Box::Horizontal, w, h),
50 push_button_(&button_box_,
51 "dropdown_select",
52 0,
53 0,
54 24,
55 get_h(),
56 g_gr->images().get("images/ui_basic/but3.png"),
57 g_gr->images().get("images/ui_basic/scrollbar_down.png"),
58 pgettext("dropdown", "Select Item")),
59 display_button_(&button_box_,
60 "dropdown_label",
61 0,
62 0,
63 w - 24,
64 get_h(),
65 g_gr->images().get("images/ui_basic/but1.png"),
66 label),
67 // Hook into parent so we can drop down outside the panel
68 list_(parent, x, y + get_h(), w, 0, ListselectLayout::kDropdown),
69 label_(label) {
70 list_.set_visible(false);
71 list_.set_background(g_gr->images().get("images/ui_basic/but1.png"));
72 display_button_.set_perm_pressed(true);
73 button_box_.add(&display_button_, UI::Align::kLeft);
74 button_box_.add(&push_button_, UI::Align::kLeft);
75 button_box_.set_size(w, get_h());
76
77 display_button_.sigclicked.connect(boost::bind(&BaseDropdown::toggle_list, this));
78 push_button_.sigclicked.connect(boost::bind(&BaseDropdown::toggle_list, this));
79 list_.clicked.connect(boost::bind(&BaseDropdown::set_value, this));
80 list_.clicked.connect(boost::bind(&BaseDropdown::toggle_list, this));
81 set_can_focus(true);
82}
83
84BaseDropdown::~BaseDropdown() {
85 clear();
86}
87
88void BaseDropdown::add(const std::string& name,
89 const uint32_t value,
90 const Image* pic,
91 const bool select_this,
92 const std::string& tooltip_text) {
93 list_.set_size(
94 list_.get_w(), std::min(list_.get_h() + list_.get_lineheight(), max_list_height_));
95 list_.add(name, value, pic, select_this, tooltip_text);
96 if (select_this) {
97 set_value();
98 }
99}
100
101bool BaseDropdown::has_selection() const {
102 return list_.has_selection();
103}
104
105uint32_t BaseDropdown::get_selected() const {
106 return list_.get_selected();
107}
108
109void BaseDropdown::set_label(const std::string& text) {
110 label_ = text;
111 display_button_.set_title(label_);
112}
113
114void BaseDropdown::set_tooltip(const std::string& text) {
115 tooltip_ = text;
116 display_button_.set_tooltip(tooltip_);
117}
118
119void BaseDropdown::set_enabled(bool on) {
120 set_can_focus(on);
121 push_button_.set_enabled(on);
122 push_button_.set_tooltip(on ? pgettext("dropdown", "Select Item") : "");
123 display_button_.set_enabled(on);
124 list_.set_visible(false);
125}
126
127void BaseDropdown::set_pos(Vector2i point) {
128 UI::Panel::set_pos(point);
129 list_.set_pos(Vector2i(point.x, point.y + get_h()));
130}
131
132void BaseDropdown::clear() {
133 list_.clear();
134 list_.set_size(list_.get_w(), 0);
135 set_layout_toplevel(false);
136}
137
138void BaseDropdown::think() {
139 if (list_.is_visible()) {
140 // Autocollapse with a bit of tolerance for the mouse movement to make it less fiddly.
141 if (!(has_focus() || list_.has_focus()) || is_mouse_away()) {
142 toggle_list();
143 }
144 }
145}
146
147uint32_t BaseDropdown::size() const {
148 return list_.size();
149}
150
151void BaseDropdown::set_value() {
152 const std::string name = list_.has_selection() ? list_.get_selected_name() :
153 /** TRANSLATORS: Selection in Dropdown menus. */
154 pgettext("dropdown", "Not Selected");
155
156 if (label_.empty()) {
157 display_button_.set_title(name);
158 } else {
159 /** TRANSLATORS: Label: Value. */
160 display_button_.set_title((boost::format(_("%1%: %2%")) % label_ % (name)).str());
161 }
162 display_button_.set_tooltip(list_.has_selection() ? list_.get_selected_tooltip() : tooltip_);
163 selected();
164 current_selection_ = list_.selection_index();
165}
166
167void BaseDropdown::toggle_list() {
168 list_.set_visible(!list_.is_visible());
169 if (list_.is_visible()) {
170 list_.move_to_top();
171 focus();
172 }
173 // Make sure that the list covers and deactivates the elements below it
174 set_layout_toplevel(list_.is_visible());
175}
176
177bool BaseDropdown::is_mouse_away() const {
178 return (get_mouse_position().x + mouse_tolerance_) < 0 ||
179 get_mouse_position().x > (get_w() + mouse_tolerance_) ||
180 (get_mouse_position().y + mouse_tolerance_ / 2) < 0 ||
181 get_mouse_position().y > (get_h() + list_.get_h() + mouse_tolerance_);
182}
183
184bool BaseDropdown::handle_key(bool down, SDL_Keysym code) {
185 if (down) {
186 switch (code.sym) {
187 case SDLK_KP_ENTER:
188 case SDLK_RETURN:
189 if (list_.is_visible()) {
190 set_value();
191 }
192 case SDLK_ESCAPE:
193 if (list_.is_visible()) {
194 list_.select(current_selection_);
195 toggle_list();
196 return true;
197 }
198 break;
199 case SDLK_DOWN:
200 if (!list_.is_visible() && !is_mouse_away()) {
201 toggle_list();
202 return true;
203 }
204 break;
205 default:
206 break; // not handled
207 }
208 }
209 if (list_.is_visible()) {
210 return list_.handle_key(down, code);
211 }
212 return false;
213}
214
215} // namespace UI
0216
=== added file 'src/ui_basic/dropdown.h'
--- src/ui_basic/dropdown.h 1970-01-01 00:00:00 +0000
+++ src/ui_basic/dropdown.h 2016-10-29 10:23:37 +0000
@@ -0,0 +1,166 @@
1/*
2 * Copyright (C) 2016 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#ifndef WL_UI_BASIC_DROPDOWN_H
21#define WL_UI_BASIC_DROPDOWN_H
22
23#include <deque>
24#include <memory>
25
26#include <boost/signals2.hpp>
27
28#include "ui_basic/box.h"
29#include "ui_basic/button.h"
30#include "ui_basic/listselect.h"
31#include "ui_basic/panel.h"
32
33namespace UI {
34
35/// Implementation for a dropdown menu that lets the user select a value.
36class BaseDropdown : public Panel {
37protected:
38 /// \param parent the parent panel
39 /// \param x the x-position within 'parent'
40 /// \param y the y-position within 'parent'
41 /// \param w the dropdown's width
42 /// \param h the maximum height for the dropdown list
43 /// \param label a label to prefix to the selected entry on the display button.
44 BaseDropdown(
45 Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, const std::string& label);
46 ~BaseDropdown();
47
48public:
49 boost::signals2::signal<void()> selected;
50
51 /// \return true if an element has been selected from the list
52 bool has_selection() const;
53
54 /// Sets a label that will be prefixed to the currently selected element's name
55 /// and displayed on the display button.
56 void set_label(const std::string& text);
57
58 /// Sets the tooltip for the display button.
59 void set_tooltip(const std::string& text);
60
61 /// Enables/disables the dropdown selection.
62 void set_enabled(bool on);
63
64 /// Move the dropdown. The dropdown's position is relative to the parent in
65 /// pixels.
66 void set_pos(Vector2i point) override;
67
68 /// The number of elements listed in the dropdown.
69 uint32_t size() const;
70
71 /// Handle keypresses
72 bool handle_key(bool down, SDL_Keysym code) override;
73
74protected:
75 /// Add an element to the list
76 /// \param name the display name of the entry
77 /// \param value the index of the entry
78 /// \param pic an image to illustrate the entry
79 /// \param select_this whether this element should be selected
80 /// \param tooltip_text a tooltip for this entry
81 void add(const std::string& name,
82 uint32_t value,
83 const Image* pic = nullptr,
84 const bool select_this = false,
85 const std::string& tooltip_text = std::string());
86
87 /// \return the index of the selected element
88 uint32_t get_selected() const;
89
90 /// Removes all elements from the list.
91 void clear();
92
93 /// Automatically collapses the list if the mouse gets too far away from the dropdown, or if it
94 /// loses focus.
95 void think() override;
96
97private:
98 /// Updates the title and tooltip of the display button and triggers a 'selected' signal.
99 void set_value();
100 /// Toggles the dropdown list on and off.
101 void toggle_list();
102
103 /// Returns true if the mouse pointer left the vicinity of the dropdown.
104 bool is_mouse_away() const;
105
106 uint32_t max_list_height_;
107 const int mouse_tolerance_; // Allow mouse outside the panel a bit before autocollapse
108 UI::Box button_box_;
109 UI::Button push_button_;
110 UI::Button display_button_;
111 UI::Listselect<uintptr_t> list_;
112 std::string label_;
113 std::string tooltip_;
114 uint32_t current_selection_;
115};
116
117/// A dropdown menu that lets the user select a value of the datatype 'Entry'.
118template <typename Entry> class Dropdown : public BaseDropdown {
119public:
120 /// \param parent the parent panel
121 /// \param x the x-position within 'parent'
122 /// \param y the y-position within 'parent'
123 /// \param w the dropdown's width
124 /// \param h the maximum height for the dropdown list
125 /// \param label a label to prefix to the selected entry on the display button.
126 /// entry.
127 Dropdown(Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, const std::string& label)
128 : BaseDropdown(parent, x, y, w, h, label) {
129 }
130 ~Dropdown() {
131 clear();
132 }
133
134 /// Add an element to the list
135 /// \param name the display name of the entry
136 /// \param value the value for the entry
137 /// \param pic an image to illustrate the entry
138 /// \param select_this whether this element should be selected
139 /// \param tooltip_text a tooltip for this entry
140 void add(const std::string& name,
141 Entry value,
142 const Image* pic = nullptr,
143 const bool select_this = false,
144 const std::string& tooltip_text = std::string()) {
145 entry_cache_.push_back(std::unique_ptr<Entry>(new Entry(value)));
146 BaseDropdown::add(name, size(), pic, select_this, tooltip_text);
147 }
148
149 /// \return the selected element
150 const Entry& get_selected() const {
151 return *entry_cache_[BaseDropdown::get_selected()];
152 }
153
154 /// Removes all elements from the list.
155 void clear() {
156 BaseDropdown::clear();
157 }
158
159private:
160 // Contains the actual elements. The BaseDropdown registers the indices only.
161 std::deque<std::unique_ptr<Entry>> entry_cache_;
162};
163
164} // namespace UI
165
166#endif // end of include guard: WL_UI_BASIC_DROPDOWN_H
0167
=== modified file 'src/ui_basic/listselect.cc'
--- src/ui_basic/listselect.cc 2016-10-16 20:35:47 +0000
+++ src/ui_basic/listselect.cc 2016-10-29 10:23:37 +0000
@@ -31,6 +31,7 @@
31#include "graphic/text/bidi.h"31#include "graphic/text/bidi.h"
32#include "graphic/text_constants.h"32#include "graphic/text_constants.h"
33#include "graphic/text_layout.h"33#include "graphic/text_layout.h"
34#include "ui_basic/mouse_constants.h"
34#include "wlapplication.h"35#include "wlapplication.h"
3536
36constexpr int kMargin = 2;37constexpr int kMargin = 2;
@@ -46,11 +47,11 @@
46 * h47 * h
47*/48*/
48BaseListselect::BaseListselect(Panel* const parent,49BaseListselect::BaseListselect(Panel* const parent,
49 int32_t const x,50 const int32_t x,
50 int32_t const y,51 const int32_t y,
51 uint32_t const w,52 const uint32_t w,
52 uint32_t const h,53 const uint32_t h,
53 bool const show_check)54 const ListselectLayout selection_mode)
54 : Panel(parent, x, y, w, h),55 : Panel(parent, x, y, w, h),
55 lineheight_(56 lineheight_(
56 UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height() +57 UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height() +
@@ -60,7 +61,8 @@
60 selection_(no_selection_index()),61 selection_(no_selection_index()),
61 last_click_time_(-10000),62 last_click_time_(-10000),
62 last_selection_(no_selection_index()),63 last_selection_(no_selection_index()),
63 show_check_(show_check) {64 selection_mode_(selection_mode),
65 background_(nullptr) {
64 set_thinks(false);66 set_thinks(false);
6567
66 scrollbar_.moved.connect(boost::bind(&BaseListselect::set_scrollpos, this, _1));68 scrollbar_.moved.connect(boost::bind(&BaseListselect::set_scrollpos, this, _1));
@@ -68,7 +70,7 @@
68 scrollbar_.set_pagesize(h - 2 * lineheight_);70 scrollbar_.set_pagesize(h - 2 * lineheight_);
69 scrollbar_.set_steps(1);71 scrollbar_.set_steps(1);
7072
71 if (show_check) {73 if (selection_mode_ == ListselectLayout::kShowCheck) {
72 uint32_t pic_h;74 uint32_t pic_h;
73 check_pic_ = g_gr->images().get("images/ui_basic/list_selected.png");75 check_pic_ = g_gr->images().get("images/ui_basic/list_selected.png");
74 max_pic_width_ = check_pic_->width();76 max_pic_width_ = check_pic_->width();
@@ -252,7 +254,7 @@
252 if (selection_ == i)254 if (selection_ == i)
253 return;255 return;
254256
255 if (show_check_) {257 if (selection_mode_ == ListselectLayout::kShowCheck) {
256 if (selection_ != no_selection_index())258 if (selection_ != no_selection_index())
257 entry_records_[selection_]->pic = nullptr;259 entry_records_[selection_]->pic = nullptr;
258 entry_records_[i]->pic = check_pic_;260 entry_records_[i]->pic = check_pic_;
@@ -274,26 +276,37 @@
274 * \return the ID/entry value of the currently selected item.276 * \return the ID/entry value of the currently selected item.
275 * The entry value is given as a parameter to \ref add277 * The entry value is given as a parameter to \ref add
276 *278 *
277 * Throws an exception when no item is selected.279 * Returns no_selection_index() if no item has been selected.
278 */280 */
279uint32_t BaseListselect::get_selected() const {281uint32_t BaseListselect::get_selected() const {
280 if (selection_ == no_selection_index())282 return selection_ < entry_records_.size() ? entry_records_[selection_]->entry_ :
281 throw NoSelection();283 no_selection_index();
282
283 return entry_records_[selection_]->entry_;
284}284}
285285
286/**286/**
287 * Remove the currently selected item. Throws an exception when no287 * Remove the currently selected item. Requires an element to have been selected first.
288 * item is selected.
289 */288 */
290void BaseListselect::remove_selected() {289void BaseListselect::remove_selected() {
291 if (selection_ == no_selection_index())290 assert(selection_ != no_selection_index());
292 throw NoSelection();
293
294 remove(selection_);291 remove(selection_);
295}292}
296293
294/**
295 * \return The name of the currently selected entry. Requires an entry to have been selected.
296 */
297const std::string& BaseListselect::get_selected_name() const {
298 assert(selection_ < entry_records_.size());
299 return entry_records_[selection_]->name;
300}
301
302/**
303 * \return The tooltip for the currently selected entry. Requires an entry to have been selected.
304 */
305const std::string& BaseListselect::get_selected_tooltip() const {
306 assert(selection_ < entry_records_.size());
307 return entry_records_[selection_]->tooltip;
308}
309
297uint32_t BaseListselect::get_lineheight() const {310uint32_t BaseListselect::get_lineheight() const {
298 return lineheight_ + kMargin;311 return lineheight_ + kMargin;
299}312}
@@ -302,27 +315,56 @@
302 return scrollbar_.is_enabled() ? get_w() - scrollbar_.get_w() : get_w();315 return scrollbar_.is_enabled() ? get_w() - scrollbar_.get_w() : get_w();
303}316}
304317
318void BaseListselect::layout() {
319 scrollbar_.set_size(scrollbar_.get_w(), get_h());
320 scrollbar_.set_pagesize(get_h() - 2 * get_lineheight());
321 scrollbar_.set_steps(entry_records_.size() * get_lineheight() - get_h());
322}
323
305/**324/**
306Redraw the listselect box325Redraw the listselect box
307*/326*/
308void BaseListselect::draw(RenderTarget& dst) {327void BaseListselect::draw(RenderTarget& dst) {
309 // draw text lines328 // draw text lines
310 const uint32_t lineheight = get_lineheight();329 const int eff_h =
311 uint32_t idx = scrollpos_ / lineheight;330 selection_mode_ == ListselectLayout::kDropdown ? get_inner_h() - 4 : get_inner_h();
312 float y = 1 + idx * lineheight - scrollpos_;331 uint32_t idx = scrollpos_ / get_lineheight();
313332 int y = 1 + idx * get_lineheight() - scrollpos_;
314 dst.brighten_rect(Rectf(0.f, 0.f, get_w(), get_h()), ms_darken_value);333
315334 if (background_ != nullptr) {
335 dst.tile(Recti(Vector2i(0, 0), get_w(), get_h()), background_, Vector2i(0, 0));
336 }
337
338 if (selection_mode_ == ListselectLayout::kDropdown) {
339 RGBAColor black(0, 0, 0, 255);
340 // left edge
341 dst.brighten_rect(Rectf(0.f, 0.f, 2.f, get_h()), BUTTON_EDGE_BRIGHT_FACTOR);
342 // bottom edge
343 dst.fill_rect(Rectf(2.f, get_h() - 2.f, get_eff_w() - 2.f, 1.f), black);
344 dst.fill_rect(Rectf(1.f, get_h() - 1.f, get_eff_w() - 1.f, 1.f), black);
345 // right edge
346 dst.fill_rect(Rectf(get_w() - 2.f, 1.f, 1.f, get_h() - 1.f), black);
347 dst.fill_rect(Rectf(get_w() - 1.f, 0.f, 1.f, get_h()), black);
348 } else {
349 dst.brighten_rect(Rectf(0.f, 0.f, get_w(), get_h()), ms_darken_value);
350 }
351
352 int lineheight = lineheight_;
316 while (idx < entry_records_.size()) {353 while (idx < entry_records_.size()) {
317 assert(get_h() < std::numeric_limits<int32_t>::max());354 assert(eff_h < std::numeric_limits<int32_t>::max());
318 if (y >= get_h()) {355
356 // Don't draw over the bottom edge
357 lineheight = std::min(eff_h - y, lineheight);
358 if (lineheight < 0) {
319 break;359 break;
320 }360 }
321361
322 const EntryRecord& er = *entry_records_[idx];362 const EntryRecord& er = *entry_records_[idx];
323363
324 Vector2f point(1.f, y);364 Vector2f point(selection_mode_ == ListselectLayout::kDropdown ? 3.f : 1.f, y);
325 uint32_t maxw = get_eff_w() - 2;365 uint32_t maxw =
366 get_eff_w() -
367 (selection_mode_ == ListselectLayout::kDropdown ? scrollbar_.is_enabled() ? 4 : 5 : 2);
326368
327 // Highlight the current selected entry369 // Highlight the current selected entry
328 if (idx == selection_) {370 if (idx == selection_) {
@@ -347,7 +389,7 @@
347 // Now draw pictures389 // Now draw pictures
348 if (er.pic) {390 if (er.pic) {
349 dst.blit(Vector2f(UI::g_fh1->fontset()->is_rtl() ? get_eff_w() - er.pic->width() - 1 : 1,391 dst.blit(Vector2f(UI::g_fh1->fontset()->is_rtl() ? get_eff_w() - er.pic->width() - 1 : 1,
350 y + (get_lineheight() - er.pic->height()) / 2.f),392 y + (lineheight_ - er.pic->height()) / 2),
351 er.pic);393 er.pic);
352 }394 }
353395
@@ -368,12 +410,18 @@
368 }410 }
369411
370 // Fix vertical position for mixed font heights412 // Fix vertical position for mixed font heights
371 if (get_lineheight() > static_cast<uint32_t>(entry_text_im->height())) {413 if (lineheight_ > static_cast<uint32_t>(entry_text_im->height())) {
372 point.y += (lineheight_ - entry_text_im->height()) / 2;414 point.y += (lineheight_ - entry_text_im->height()) / 2;
373 } else {415 } else {
374 point.y -= (entry_text_im->height() - lineheight_) / 2;416 point.y -= (entry_text_im->height() - lineheight_) / 2;
375 }417 }
376418
419 // Don't draw over the bottom edge
420 lineheight = std::min(eff_h - static_cast<int>(point.y), lineheight);
421 if (lineheight < 0) {
422 break;
423 }
424
377 // Crop to column width while blitting425 // Crop to column width while blitting
378 if (static_cast<int>(alignment & UI::Align::kRight) &&426 if (static_cast<int>(alignment & UI::Align::kRight) &&
379 (maxw + picw) < static_cast<uint32_t>(entry_text_im->width())) {427 (maxw + picw) < static_cast<uint32_t>(entry_text_im->width())) {
@@ -382,13 +430,13 @@
382430
383 // We want this always on, e.g. for mixed language savegame filenames, or the languages431 // We want this always on, e.g. for mixed language savegame filenames, or the languages
384 // list432 // list
385 dst.blitrect(point, entry_text_im,433 dst.blitrect(point, entry_text_im, Recti(entry_text_im->width() - maxw + picw, 0, maxw,
386 Recti(entry_text_im->width() - maxw + picw, 0, maxw, entry_text_im->height()));434 entry_text_im->height()));
387 } else {435 } else {
388 dst.blitrect(point, entry_text_im, Recti(0, 0, maxw, entry_text_im->height()));436 dst.blitrect(point, entry_text_im, Recti(0, 0, maxw, lineheight));
389 }437 }
390438
391 y += lineheight;439 y += get_lineheight();
392 ++idx;440 ++idx;
393 }441 }
394}442}
@@ -445,6 +493,9 @@
445 set_tooltip("");493 set_tooltip("");
446 return false;494 return false;
447 }495 }
496 if (selection_mode_ == ListselectLayout::kDropdown) {
497 select(y);
498 }
448 set_tooltip(entry_records_.at(y)->tooltip);499 set_tooltip(entry_records_.at(y)->tooltip);
449 return true;500 return true;
450}501}
451502
=== modified file 'src/ui_basic/listselect.h'
--- src/ui_basic/listselect.h 2016-08-04 15:49:05 +0000
+++ src/ui_basic/listselect.h 2016-10-29 10:23:37 +0000
@@ -32,6 +32,12 @@
32namespace UI {32namespace UI {
33struct Scrollbar;33struct Scrollbar;
3434
35enum class ListselectLayout {
36 kPlain, // Highlight the selected element
37 kDropdown, // When the mouse moves, instantly select the element that the mouse hovers over
38 kShowCheck // Show a green arrow in front of the selected element
39};
40
35/**41/**
36 * This class defines a list-select box whose entries are defined by a name42 * This class defines a list-select box whose entries are defined by a name
37 * and an associated numeric ID.43 * and an associated numeric ID.
@@ -39,8 +45,12 @@
39 * Use the \ref Listselect template to use arbitrary IDs.45 * Use the \ref Listselect template to use arbitrary IDs.
40 */46 */
41struct BaseListselect : public Panel {47struct BaseListselect : public Panel {
42 BaseListselect(48 BaseListselect(Panel* parent,
43 Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, bool show_check = false);49 int32_t x,
50 int32_t y,
51 uint32_t w,
52 uint32_t h,
53 ListselectLayout selection_mode = ListselectLayout::kPlain);
44 ~BaseListselect();54 ~BaseListselect();
4555
46 boost::signals2::signal<void(uint32_t)> selected;56 boost::signals2::signal<void(uint32_t)> selected;
@@ -88,15 +98,23 @@
88 void select(uint32_t i);98 void select(uint32_t i);
89 bool has_selection() const;99 bool has_selection() const;
90100
91 struct NoSelection {};
92 uint32_t get_selected() const;101 uint32_t get_selected() const;
93 void remove_selected();102 void remove_selected();
94103
104 const std::string& get_selected_name() const;
105 const std::string& get_selected_tooltip() const;
106
107 void set_background(const Image* background) {
108 background_ = background;
109 }
110
95 /// Return the total height (text + spacing) occupied by a single line.111 /// Return the total height (text + spacing) occupied by a single line.
96 uint32_t get_lineheight() const;112 uint32_t get_lineheight() const;
97113
98 uint32_t get_eff_w() const;114 uint32_t get_eff_w() const;
99115
116 void layout() override;
117
100 // Drawing and event handling118 // Drawing and event handling
101 void draw(RenderTarget&) override;119 void draw(RenderTarget&) override;
102 bool handle_mousepress(uint8_t btn, int32_t x, int32_t y) override;120 bool handle_mousepress(uint8_t btn, int32_t x, int32_t y) override;
@@ -132,14 +150,20 @@
132 uint32_t selection_;150 uint32_t selection_;
133 uint32_t last_click_time_;151 uint32_t last_click_time_;
134 uint32_t last_selection_; // for double clicks152 uint32_t last_selection_; // for double clicks
135 bool show_check_; // show a green arrow left of selected element153 ListselectLayout selection_mode_;
136 const Image* check_pic_;154 const Image* check_pic_;
155 const Image* background_;
137 std::string current_tooltip_;156 std::string current_tooltip_;
138};157};
139158
140template <typename Entry> struct Listselect : public BaseListselect {159template <typename Entry> struct Listselect : public BaseListselect {
141 Listselect(Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, bool show_check = false)160 Listselect(Panel* parent,
142 : BaseListselect(parent, x, y, w, h, show_check) {161 int32_t x,
162 int32_t y,
163 uint32_t w,
164 uint32_t h,
165 ListselectLayout selection_mode = ListselectLayout::kPlain)
166 : BaseListselect(parent, x, y, w, h, selection_mode) {
143 }167 }
144168
145 void add(const std::string& name,169 void add(const std::string& name,
@@ -167,6 +191,10 @@
167 return entry_cache_[BaseListselect::get_selected()];191 return entry_cache_[BaseListselect::get_selected()];
168 }192 }
169193
194 void set_background(const Image* background) {
195 BaseListselect::set_background(background);
196 }
197
170private:198private:
171 std::deque<Entry> entry_cache_;199 std::deque<Entry> entry_cache_;
172};200};
@@ -181,8 +209,13 @@
181template <typename Entry> struct Listselect<Entry&> : public Listselect<Entry*> {209template <typename Entry> struct Listselect<Entry&> : public Listselect<Entry*> {
182 using Base = Listselect<Entry*>;210 using Base = Listselect<Entry*>;
183211
184 Listselect(Panel* parent, int32_t x, int32_t y, uint32_t w, uint32_t h, bool show_check = false)212 Listselect(Panel* parent,
185 : Base(parent, x, y, w, h, show_check) {213 int32_t x,
214 int32_t y,
215 uint32_t w,
216 uint32_t h,
217 ListselectLayout selection_mode = ListselectLayout::kPlain)
218 : Base(parent, x, y, w, h, selection_mode) {
186 }219 }
187220
188 void add(const std::string& name,221 void add(const std::string& name,
@@ -207,6 +240,10 @@
207 Entry& get_selected() const {240 Entry& get_selected() const {
208 return *Base::get_selected();241 return *Base::get_selected();
209 }242 }
243
244 void set_background(const Image* background) {
245 *Base::set_background(background);
246 }
210};247};
211}248}
212249
213250
=== modified file 'src/ui_basic/panel.cc'
--- src/ui_basic/panel.cc 2016-10-16 20:35:47 +0000
+++ src/ui_basic/panel.cc 2016-10-29 10:23:37 +0000
@@ -820,7 +820,7 @@
820 // Found a child at the position820 // Found a child at the position
821 if (child->do_mousewheel(821 if (child->do_mousewheel(
822 which, x, y, rel_mouse_pos - Vector2i(child->get_x() + child->get_lborder(),822 which, x, y, rel_mouse_pos - Vector2i(child->get_x() + child->get_lborder(),
823 child->get_y() + child->get_tborder()))) {823 child->get_y() + child->get_tborder()))) {
824 return true;824 return true;
825 }825 }
826 // Break after the first hit panel in the list. The panels are ordered from top to bottom,826 // Break after the first hit panel in the list. The panels are ordered from top to bottom,
827827
=== modified file 'src/ui_basic/panel.h'
--- src/ui_basic/panel.h 2016-10-16 09:31:42 +0000
+++ src/ui_basic/panel.h 2016-10-29 10:23:37 +0000
@@ -113,7 +113,7 @@
113 // Geometry113 // Geometry
114 void set_size(int nw, int nh);114 void set_size(int nw, int nh);
115 void set_desired_size(int w, int h);115 void set_desired_size(int w, int h);
116 void set_pos(Vector2i);116 virtual void set_pos(Vector2i);
117 virtual void move_inside_parent();117 virtual void move_inside_parent();
118 virtual void layout();118 virtual void layout();
119119
120120
=== modified file 'src/ui_basic/progressbar.cc'
--- src/ui_basic/progressbar.cc 2016-10-16 20:35:47 +0000
+++ src/ui_basic/progressbar.cc 2016-10-29 10:23:37 +0000
@@ -67,8 +67,8 @@
67 assert(fraction <= 1);67 assert(fraction <= 1);
6868
69 const RGBColor color = fraction <= 0.33f ? RGBColor(255, 0, 0) : fraction <= 0.67f ?69 const RGBColor color = fraction <= 0.33f ? RGBColor(255, 0, 0) : fraction <= 0.67f ?
70 RGBColor(255, 255, 0) :70 RGBColor(255, 255, 0) :
71 RGBColor(0, 255, 0);71 RGBColor(0, 255, 0);
7272
73 // Draw the actual bar73 // Draw the actual bar
74 if (orientation_ == Horizontal) {74 if (orientation_ == Horizontal) {
7575
=== modified file 'src/ui_basic/scrollbar.cc'
--- src/ui_basic/scrollbar.cc 2016-10-23 12:59:11 +0000
+++ src/ui_basic/scrollbar.cc 2016-10-29 10:23:37 +0000
@@ -271,7 +271,8 @@
271 dst.fill_rect(Rectf(r.origin() + Vector2f(r.w - 1, 1), 1, r.h - 1), black);271 dst.fill_rect(Rectf(r.origin() + Vector2f(r.w - 1, 1), 1, r.h - 1), black);
272 } else {272 } else {
273 // bottom edge273 // bottom edge
274 dst.brighten_rect(Rectf(r.origin() + Vector2f(0, r.h - 2), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);274 dst.brighten_rect(
275 Rectf(r.origin() + Vector2f(0, r.h - 2), r.w, 2), BUTTON_EDGE_BRIGHT_FACTOR);
275 // right edge276 // right edge
276 dst.brighten_rect(277 dst.brighten_rect(
277 Rectf(r.origin() + Vector2f(r.w - 2, 0), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);278 Rectf(r.origin() + Vector2f(r.w - 2, 0), 2, r.h - 2), BUTTON_EDGE_BRIGHT_FACTOR);
278279
=== modified file 'src/ui_basic/slider.cc'
--- src/ui_basic/slider.cc 2016-10-16 20:35:47 +0000
+++ src/ui_basic/slider.cc 2016-10-29 10:23:37 +0000
@@ -75,6 +75,7 @@
75 bar_size_(bar_size),75 bar_size_(bar_size),
76 cursor_size_(cursor_size) {76 cursor_size_(cursor_size) {
77 set_thinks(false);77 set_thinks(false);
78 set_can_focus(true);
78 calculate_cursor_position();79 calculate_cursor_position();
79}80}
8081
@@ -200,6 +201,7 @@
200 if (enabled_ == enabled)201 if (enabled_ == enabled)
201 return;202 return;
202203
204 set_can_focus(enabled);
203 enabled_ = enabled;205 enabled_ = enabled;
204 if (!enabled) {206 if (!enabled) {
205 pressed_ = false;207 pressed_ = false;
@@ -399,6 +401,7 @@
399 if (btn != SDL_BUTTON_LEFT)401 if (btn != SDL_BUTTON_LEFT)
400 return false;402 return false;
401403
404 focus();
402 if (x >= cursor_pos_ && x <= cursor_pos_ + cursor_size_) {405 if (x >= cursor_pos_ && x <= cursor_pos_ + cursor_size_) {
403 // click on cursor406 // click on cursor
404 cursor_pressed(x);407 cursor_pressed(x);
@@ -469,6 +472,7 @@
469 if (btn != SDL_BUTTON_LEFT)472 if (btn != SDL_BUTTON_LEFT)
470 return false;473 return false;
471474
475 focus();
472 if (y >= cursor_pos_ && y <= cursor_pos_ + cursor_size_) {476 if (y >= cursor_pos_ && y <= cursor_pos_ + cursor_size_) {
473 // click on cursor477 // click on cursor
474 cursor_pressed(y);478 cursor_pressed(y);
475479
=== modified file 'src/ui_basic/tabpanel.cc'
--- src/ui_basic/tabpanel.cc 2016-10-16 20:35:47 +0000
+++ src/ui_basic/tabpanel.cc 2016-10-29 10:23:37 +0000
@@ -260,13 +260,13 @@
260 if (pic_background_) {260 if (pic_background_) {
261 if (!tabs_.empty()) {261 if (!tabs_.empty()) {
262 dst.tile(Recti(Vector2i(0, 0), tabs_.back()->get_x() + tabs_.back()->get_w(),262 dst.tile(Recti(Vector2i(0, 0), tabs_.back()->get_x() + tabs_.back()->get_w(),
263 kTabPanelButtonHeight - 2),263 kTabPanelButtonHeight - 2),
264 pic_background_, Vector2i(get_x(), get_y()));264 pic_background_, Vector2i(get_x(), get_y()));
265 }265 }
266 assert(kTabPanelButtonHeight - 2 <= get_h());266 assert(kTabPanelButtonHeight - 2 <= get_h());
267 dst.tile(267 dst.tile(Recti(Vector2i(0, kTabPanelButtonHeight - 2), get_w(),
268 Recti(Vector2i(0, kTabPanelButtonHeight - 2), get_w(), get_h() - kTabPanelButtonHeight + 2),268 get_h() - kTabPanelButtonHeight + 2),
269 pic_background_, Vector2i(get_x(), get_y() + kTabPanelButtonHeight - 2));269 pic_background_, Vector2i(get_x(), get_y() + kTabPanelButtonHeight - 2));
270 }270 }
271271
272 RGBColor black(0, 0, 0);272 RGBColor black(0, 0, 0);
@@ -279,8 +279,7 @@
279 tab_width = tabs_[idx]->get_w();279 tab_width = tabs_[idx]->get_w();
280280
281 if (highlight_ == idx) {281 if (highlight_ == idx) {
282 dst.brighten_rect(282 dst.brighten_rect(Rectf(x, 0, tab_width, kTabPanelButtonHeight), MOUSE_OVER_BRIGHT_FACTOR);
283 Rectf(x, 0, tab_width, kTabPanelButtonHeight), MOUSE_OVER_BRIGHT_FACTOR);
284 }283 }
285284
286 assert(tabs_[idx]->pic);285 assert(tabs_[idx]->pic);
@@ -297,13 +296,13 @@
297 uint16_t picture_height = image_scale * tabs_[idx]->pic->height();296 uint16_t picture_height = image_scale * tabs_[idx]->pic->height();
298 dst.blitrect_scale(297 dst.blitrect_scale(
299 Rectf(x + (kTabPanelButtonHeight - picture_width) / 2.f,298 Rectf(x + (kTabPanelButtonHeight - picture_width) / 2.f,
300 (kTabPanelButtonHeight - picture_height) / 2.f, picture_width, picture_height),299 (kTabPanelButtonHeight - picture_height) / 2.f, picture_width, picture_height),
301 tabs_[idx]->pic, Recti(0, 0, tabs_[idx]->pic->width(), tabs_[idx]->pic->height()), 1.,300 tabs_[idx]->pic, Recti(0, 0, tabs_[idx]->pic->width(), tabs_[idx]->pic->height()), 1.,
302 BlendMode::UseAlpha);301 BlendMode::UseAlpha);
303 } else {302 } else {
304 dst.blit(303 dst.blit(Vector2f(x + kTabPanelTextMargin,
305 Vector2f(x + kTabPanelTextMargin, (kTabPanelButtonHeight - tabs_[idx]->pic->height()) / 2.f),304 (kTabPanelButtonHeight - tabs_[idx]->pic->height()) / 2.f),
306 tabs_[idx]->pic, BlendMode::UseAlpha, UI::Align::kLeft);305 tabs_[idx]->pic, BlendMode::UseAlpha, UI::Align::kLeft);
307 }306 }
308307
309 // Draw top part of border308 // Draw top part of border
@@ -317,8 +316,7 @@
317 dst.brighten_rect(316 dst.brighten_rect(
318 Rectf(x, kTabPanelButtonHeight - 2, tab_width, 2), 2 * BUTTON_EDGE_BRIGHT_FACTOR);317 Rectf(x, kTabPanelButtonHeight - 2, tab_width, 2), 2 * BUTTON_EDGE_BRIGHT_FACTOR);
319 else {318 else {
320 dst.brighten_rect(319 dst.brighten_rect(Rectf(x, kTabPanelButtonHeight - 2, 2, 2), BUTTON_EDGE_BRIGHT_FACTOR);
321 Rectf(x, kTabPanelButtonHeight - 2, 2, 2), BUTTON_EDGE_BRIGHT_FACTOR);
322320
323 dst.brighten_rect(Rectf(x + tab_width - 2, kTabPanelButtonHeight - 2, 2, 2),321 dst.brighten_rect(Rectf(x + tab_width - 2, kTabPanelButtonHeight - 2, 2, 2),
324 2 * BUTTON_EDGE_BRIGHT_FACTOR);322 2 * BUTTON_EDGE_BRIGHT_FACTOR);
325323
=== modified file 'src/ui_basic/window.cc'
--- src/ui_basic/window.cc 2016-10-23 12:59:11 +0000
+++ src/ui_basic/window.cc 2016-10-29 10:23:37 +0000
@@ -226,7 +226,7 @@
226 Panel& parent = *get_parent();226 Panel& parent = *get_parent();
227227
228 set_pos(Vector2i((static_cast<int32_t>(parent.get_inner_w()) - get_w()) / 2,228 set_pos(Vector2i((static_cast<int32_t>(parent.get_inner_w()) - get_w()) / 2,
229 (static_cast<int32_t>(parent.get_inner_h()) - get_h()) / 2));229 (static_cast<int32_t>(parent.get_inner_h()) - get_h()) / 2));
230}230}
231231
232/**232/**
@@ -234,7 +234,8 @@
234 */234 */
235void Window::draw(RenderTarget& dst) {235void Window::draw(RenderTarget& dst) {
236 if (!is_minimal()) {236 if (!is_minimal()) {
237 dst.tile(Recti(Vector2i(0, 0), get_inner_w(), get_inner_h()), pic_background_, Vector2i(0, 0));237 dst.tile(
238 Recti(Vector2i(0, 0), get_inner_w(), get_inner_h()), pic_background_, Vector2i(0, 0));
238 }239 }
239}240}
240241
@@ -257,8 +258,9 @@
257 // top bar258 // top bar
258 static_assert(0 <= HZ_B_CORNER_PIXMAP_LEN, "assert(0 <= HZ_B_CORNER_PIXMAP_LEN) failed.");259 static_assert(0 <= HZ_B_CORNER_PIXMAP_LEN, "assert(0 <= HZ_B_CORNER_PIXMAP_LEN) failed.");
259 for (; pos < hz_bar_end_minus_middle; pos += HZ_B_MIDDLE_PIXMAP_LEN)260 for (; pos < hz_bar_end_minus_middle; pos += HZ_B_MIDDLE_PIXMAP_LEN)
260 dst.blitrect(Vector2f(pos, 0), pic_top_, Recti(Vector2i(HZ_B_CORNER_PIXMAP_LEN, 0),261 dst.blitrect(
261 HZ_B_MIDDLE_PIXMAP_LEN, TP_B_PIXMAP_THICKNESS));262 Vector2f(pos, 0), pic_top_, Recti(Vector2i(HZ_B_CORNER_PIXMAP_LEN, 0),
263 HZ_B_MIDDLE_PIXMAP_LEN, TP_B_PIXMAP_THICKNESS));
262264
263 // odd pixels of top bar and top right corner265 // odd pixels of top bar and top right corner
264 const int32_t width = hz_bar_end - pos + HZ_B_CORNER_PIXMAP_LEN;266 const int32_t width = hz_bar_end - pos + HZ_B_CORNER_PIXMAP_LEN;
@@ -295,15 +297,16 @@
295 // left bar297 // left bar
296 static_assert(0 <= VT_B_THINGY_PIXMAP_LEN, "assert(0 <= VT_B_THINGY_PIXMAP_LEN) failed.");298 static_assert(0 <= VT_B_THINGY_PIXMAP_LEN, "assert(0 <= VT_B_THINGY_PIXMAP_LEN) failed.");
297 for (; pos < vt_bar_end_minus_middle; pos += VT_B_MIDDLE_PIXMAP_LEN)299 for (; pos < vt_bar_end_minus_middle; pos += VT_B_MIDDLE_PIXMAP_LEN)
298 dst.blitrect(300 dst.blitrect(Vector2f(0, pos), pic_lborder_,
299 Vector2f(0, pos), pic_lborder_, Recti(Vector2i(0, VT_B_THINGY_PIXMAP_LEN),301 Recti(Vector2i(0, VT_B_THINGY_PIXMAP_LEN), VT_B_PIXMAP_THICKNESS,
300 VT_B_PIXMAP_THICKNESS, VT_B_MIDDLE_PIXMAP_LEN));302 VT_B_MIDDLE_PIXMAP_LEN));
301303
302 // odd pixels of left bar and left bottom thingy304 // odd pixels of left bar and left bottom thingy
303 const int32_t height = vt_bar_end - pos + VT_B_THINGY_PIXMAP_LEN;305 const int32_t height = vt_bar_end - pos + VT_B_THINGY_PIXMAP_LEN;
304 assert(0 <= VT_B_TOTAL_PIXMAP_LEN - height);306 assert(0 <= VT_B_TOTAL_PIXMAP_LEN - height);
305 dst.blitrect(Vector2f(0, pos), pic_lborder_, Recti(Vector2i(0, VT_B_TOTAL_PIXMAP_LEN - height),307 dst.blitrect(
306 VT_B_PIXMAP_THICKNESS, height));308 Vector2f(0, pos), pic_lborder_,
309 Recti(Vector2i(0, VT_B_TOTAL_PIXMAP_LEN - height), VT_B_PIXMAP_THICKNESS, height));
307 }310 }
308311
309 { // Right border312 { // Right border
@@ -320,7 +323,7 @@
320 for (; pos < vt_bar_end_minus_middle; pos += VT_B_MIDDLE_PIXMAP_LEN)323 for (; pos < vt_bar_end_minus_middle; pos += VT_B_MIDDLE_PIXMAP_LEN)
321 dst.blitrect(Vector2f(right_border_x, pos), pic_rborder_,324 dst.blitrect(Vector2f(right_border_x, pos), pic_rborder_,
322 Recti(Vector2i(0, VT_B_THINGY_PIXMAP_LEN), VT_B_PIXMAP_THICKNESS,325 Recti(Vector2i(0, VT_B_THINGY_PIXMAP_LEN), VT_B_PIXMAP_THICKNESS,
323 VT_B_MIDDLE_PIXMAP_LEN));326 VT_B_MIDDLE_PIXMAP_LEN));
324327
325 // odd pixels of right bar and right bottom thingy328 // odd pixels of right bar and right bottom thingy
326 const int32_t height = vt_bar_end - pos + VT_B_THINGY_PIXMAP_LEN;329 const int32_t height = vt_bar_end - pos + VT_B_THINGY_PIXMAP_LEN;
@@ -340,12 +343,13 @@
340 for (; pos < hz_bar_end_minus_middle; pos += HZ_B_MIDDLE_PIXMAP_LEN)343 for (; pos < hz_bar_end_minus_middle; pos += HZ_B_MIDDLE_PIXMAP_LEN)
341 dst.blitrect(Vector2f(pos, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,344 dst.blitrect(Vector2f(pos, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
342 Recti(Vector2i(HZ_B_CORNER_PIXMAP_LEN, 0), HZ_B_MIDDLE_PIXMAP_LEN,345 Recti(Vector2i(HZ_B_CORNER_PIXMAP_LEN, 0), HZ_B_MIDDLE_PIXMAP_LEN,
343 BT_B_PIXMAP_THICKNESS));346 BT_B_PIXMAP_THICKNESS));
344347
345 // odd pixels of bottom bar and bottom right corner348 // odd pixels of bottom bar and bottom right corner
346 const int32_t width = hz_bar_end - pos + HZ_B_CORNER_PIXMAP_LEN;349 const int32_t width = hz_bar_end - pos + HZ_B_CORNER_PIXMAP_LEN;
347 dst.blitrect(Vector2f(pos, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,350 dst.blitrect(
348 Recti(Vector2i(HZ_B_TOTAL_PIXMAP_LEN - width, 0), width, BT_B_PIXMAP_THICKNESS));351 Vector2f(pos, get_h() - BT_B_PIXMAP_THICKNESS), pic_bottom_,
352 Recti(Vector2i(HZ_B_TOTAL_PIXMAP_LEN - width, 0), width, BT_B_PIXMAP_THICKNESS));
349 }353 }
350 }354 }
351}355}
352356
=== modified file 'src/ui_fsmenu/launch_mpg.cc'
--- src/ui_fsmenu/launch_mpg.cc 2016-10-25 07:07:14 +0000
+++ src/ui_fsmenu/launch_mpg.cc 2016-10-29 10:23:37 +0000
@@ -650,7 +650,7 @@
650 suggested_teams_box_->show(map.get_suggested_teams());650 suggested_teams_box_->show(map.get_suggested_teams());
651 suggested_teams_box_->set_pos(651 suggested_teams_box_->set_pos(
652 Vector2i(suggested_teams_box_->get_x(),652 Vector2i(suggested_teams_box_->get_x(),
653 back_.get_y() - padding_ - suggested_teams_box_->get_h() - padding_));653 back_.get_y() - padding_ - suggested_teams_box_->get_h() - padding_));
654}654}
655655
656/// Show help656/// Show help
657657
=== modified file 'src/ui_fsmenu/launch_spg.cc'
--- src/ui_fsmenu/launch_spg.cc 2016-10-24 14:05:58 +0000
+++ src/ui_fsmenu/launch_spg.cc 2016-10-29 10:23:37 +0000
@@ -33,7 +33,6 @@
33#include "logic/game.h"33#include "logic/game.h"
34#include "logic/game_controller.h"34#include "logic/game_controller.h"
35#include "logic/game_settings.h"35#include "logic/game_settings.h"
36#include "logic/map.h"
37#include "logic/map_objects/map_object.h"36#include "logic/map_objects/map_object.h"
38#include "logic/player.h"37#include "logic/player.h"
39#include "map_io/map_loader.h"38#include "map_io/map_loader.h"
@@ -61,14 +60,12 @@
61 buth_,60 buth_,
62 g_gr->images().get("images/ui_basic/but1.png"),61 g_gr->images().get("images/ui_basic/but1.png"),
63 _("Select map")),62 _("Select map")),
64 wincondition_(this,63 win_condition_dropdown_(this,
65 "win_condition",64 get_w() * 7 / 10,
66 get_w() * 7 / 10,65 get_h() * 4 / 10 + buth_,
67 get_h() * 4 / 10 + buth_,66 butw_,
68 butw_,67 get_h() - get_h() * 4 / 10 - buth_,
69 buth_,68 ""),
70 g_gr->images().get("images/ui_basic/but1.png"),
71 ""),
72 back_(this,69 back_(this,
73 "back",70 "back",
74 get_w() * 7 / 10,71 get_w() * 7 / 10,
@@ -127,15 +124,12 @@
127 is_scenario_(false) {124 is_scenario_(false) {
128 select_map_.sigclicked.connect(125 select_map_.sigclicked.connect(
129 boost::bind(&FullscreenMenuLaunchSPG::select_map, boost::ref(*this)));126 boost::bind(&FullscreenMenuLaunchSPG::select_map, boost::ref(*this)));
130 wincondition_.sigclicked.connect(127 win_condition_dropdown_.selected.connect(
131 boost::bind(&FullscreenMenuLaunchSPG::win_condition_clicked, boost::ref(*this)));128 boost::bind(&FullscreenMenuLaunchSPG::win_condition_selected, this));
132 back_.sigclicked.connect(boost::bind(&FullscreenMenuLaunchSPG::clicked_back, boost::ref(*this)));129 back_.sigclicked.connect(boost::bind(&FullscreenMenuLaunchSPG::clicked_back, boost::ref(*this)));
133 ok_.sigclicked.connect(boost::bind(&FullscreenMenuLaunchSPG::clicked_ok, boost::ref(*this)));130 ok_.sigclicked.connect(boost::bind(&FullscreenMenuLaunchSPG::clicked_ok, boost::ref(*this)));
134131
135 lua_ = new LuaInterface();132 lua_ = new LuaInterface();
136 win_condition_scripts_ = settings_->settings().win_condition_scripts;
137 cur_wincondition_ = -1;
138 win_condition_clicked();
139133
140 title_.set_fontsize(UI_FONT_SIZE_BIG);134 title_.set_fontsize(UI_FONT_SIZE_BIG);
141135
@@ -203,68 +197,113 @@
203}197}
204198
205/**199/**
206 * WinCondition button has been pressed200 * Fill the dropdown with the available win conditions.
207 */201 */
208void FullscreenMenuLaunchSPG::win_condition_clicked() {202void FullscreenMenuLaunchSPG::update_win_conditions() {
209 if (settings_->can_change_map()) {203 win_condition_dropdown_.clear();
210 cur_wincondition_++;
211 cur_wincondition_ %= win_condition_scripts_.size();
212 settings_->set_win_condition_script(win_condition_scripts_[cur_wincondition_]);
213 }
214
215 win_condition_update();
216}
217
218/**
219 * update win conditions information
220 */
221void FullscreenMenuLaunchSPG::win_condition_update() {
222 if (settings_->settings().scenario) {204 if (settings_->settings().scenario) {
223 wincondition_.set_title(_("Scenario"));205 win_condition_dropdown_.set_label(_("Scenario"));
224 wincondition_.set_tooltip(_("Win condition is set through the scenario"));206 win_condition_dropdown_.set_tooltip(_("Win condition is set through the scenario"));
207 win_condition_dropdown_.set_enabled(false);
225 } else {208 } else {
226 win_condition_load();209 win_condition_dropdown_.set_label("");
227 }210 win_condition_dropdown_.set_tooltip("");
228}211 Widelands::Map map;
229212 std::unique_ptr<Widelands::MapLoader> ml =
230/**213 map.get_correct_loader(settings_->settings().mapfilename);
231 * Loads the current win condition script from the settings provider.214 if (ml != nullptr) {
232 * Calls win_condition_clicked() if the current map can't handle the win condition.215 ml->preload_map(true);
233 */216 load_win_conditions(map);
234void FullscreenMenuLaunchSPG::win_condition_load() {217 } else {
218 const std::string error_message =
219 (boost::format(_("Unable to determine valid win conditions because the map '%s' could "
220 "not be loaded.")) %
221 settings_->settings().mapfilename)
222 .str();
223 win_condition_dropdown_.set_label(_("Error"));
224 win_condition_dropdown_.set_tooltip(error_message);
225 log("LaunchSPG: No map loader: %s\n", error_message.c_str());
226 }
227 win_condition_dropdown_.set_enabled(true);
228 }
229}
230
231void FullscreenMenuLaunchSPG::load_win_conditions(const Widelands::Map& map) {
232 try {
233 const std::set<std::string> tags = map.get_tags();
234 // Make sure that the last win condition is still valid. If not, pick the first one
235 // available.
236 if (last_win_condition_.empty()) {
237 last_win_condition_ = settings_->settings().win_condition_scripts.front();
238 }
239 std::unique_ptr<LuaTable> t = win_condition_if_valid(last_win_condition_, tags);
240 for (const std::string& win_condition_script : settings_->settings().win_condition_scripts) {
241 if (t) {
242 break;
243 } else {
244 last_win_condition_ = win_condition_script;
245 t = win_condition_if_valid(last_win_condition_, tags);
246 }
247 }
248
249 // Now fill the dropdown.
250 for (const std::string& win_condition_script : settings_->settings().win_condition_scripts) {
251 try {
252 t = win_condition_if_valid(win_condition_script, tags);
253 if (t) {
254 i18n::Textdomain td("win_conditions");
255 win_condition_dropdown_.add(_(t->get_string("name")), win_condition_script, nullptr,
256 win_condition_script == last_win_condition_,
257 t->get_string("description"));
258 }
259 } catch (LuaTableKeyError& e) {
260 log("LaunchSPG: Error loading win condition: %s %s\n", win_condition_script.c_str(),
261 e.what());
262 }
263 }
264 } catch (const std::exception& e) {
265 const std::string error_message =
266 (boost::format(_("Unable to determine valid win conditions because the map '%s' "
267 "could not be loaded.")) %
268 settings_->settings().mapfilename)
269 .str();
270 win_condition_dropdown_.set_label(_("Error"));
271 win_condition_dropdown_.set_tooltip(error_message);
272 log("LaunchSPG: Exception: %s %s\n", error_message.c_str(), e.what());
273 }
274}
275
276void FullscreenMenuLaunchSPG::win_condition_selected() {
277 last_win_condition_ = win_condition_dropdown_.get_selected();
278}
279
280// TODO(GunChleoc): Turn this into a free standing function. It seems it is not using any state.
281std::unique_ptr<LuaTable>
282FullscreenMenuLaunchSPG::win_condition_if_valid(const std::string& win_condition_script,
283 std::set<std::string> tags) const {
235 bool is_usable = true;284 bool is_usable = true;
285 std::unique_ptr<LuaTable> t;
236 try {286 try {
237 std::unique_ptr<LuaTable> t = lua_->run_script(settings_->get_win_condition_script());287 t = lua_->run_script(win_condition_script);
238 t->do_not_warn_about_unaccessed_keys();288 t->do_not_warn_about_unaccessed_keys();
239289
240 // Skip this win condition if the map doesn't have all the required tags290 // Skip this win condition if the map doesn't have all the required tags
241 if (t->has_key("map_tags") && !settings_->settings().mapfilename.empty()) {291 if (t->has_key("map_tags")) {
242 Widelands::Map map;
243 std::unique_ptr<Widelands::MapLoader> ml =
244 map.get_correct_loader(settings_->settings().mapfilename);
245 ml->preload_map(true);
246 for (const std::string& map_tag : t->get_table("map_tags")->array_entries<std::string>()) {292 for (const std::string& map_tag : t->get_table("map_tags")->array_entries<std::string>()) {
247 if (!map.has_tag(map_tag)) {293 if (!tags.count(map_tag)) {
248 is_usable = false;294 is_usable = false;
249 break;295 break;
250 }296 }
251 }297 }
252 }298 }
253299 } catch (LuaTableKeyError& e) {
254 const std::string name = t->get_string("name");300 log(
255 const std::string descr = t->get_string("description");301 "LaunchSPG: Error loading win condition: %s %s\n", win_condition_script.c_str(), e.what());
256 {
257 i18n::Textdomain td("win_conditions");
258 wincondition_.set_title(_(name));
259 }
260 wincondition_.set_tooltip(descr.c_str());
261 } catch (LuaTableKeyError&) {
262 // might be that this is not a win condition after all.
263 is_usable = false;
264 }302 }
265 if (!is_usable) {303 if (!is_usable) {
266 win_condition_clicked();304 t.reset(nullptr);
267 }305 }
306 return t;
268}307}
269308
270/**309/**
@@ -285,6 +324,7 @@
285 if (is_scenario_) {324 if (is_scenario_) {
286 end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kScenarioGame);325 end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kScenarioGame);
287 } else {326 } else {
327 settings_->set_win_condition_script(win_condition_dropdown_.get_selected());
288 end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kNormalGame);328 end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kNormalGame);
289 }329 }
290 }330 }
@@ -310,7 +350,6 @@
310350
311 select_map_.set_visible(settings_->can_change_map());351 select_map_.set_visible(settings_->can_change_map());
312 select_map_.set_enabled(settings_->can_change_map());352 select_map_.set_enabled(settings_->can_change_map());
313 wincondition_.set_enabled(settings_->can_change_map() && !settings.scenario);
314353
315 if (settings.scenario) {354 if (settings.scenario) {
316 set_scenario_values();355 set_scenario_values();
@@ -329,8 +368,6 @@
329 // update the player description groups368 // update the player description groups
330 for (uint32_t i = 0; i < kMaxPlayers; ++i)369 for (uint32_t i = 0; i < kMaxPlayers; ++i)
331 players_[i]->refresh();370 players_[i]->refresh();
332
333 win_condition_update();
334}371}
335372
336/**373/**
@@ -357,6 +394,7 @@
357394
358 safe_place_for_host(nr_players_);395 safe_place_for_host(nr_players_);
359 settings_->set_map(mapdata.name, mapdata.filename, nr_players_);396 settings_->set_map(mapdata.name, mapdata.filename, nr_players_);
397 update_win_conditions();
360}398}
361399
362/**400/**
363401
=== modified file 'src/ui_fsmenu/launch_spg.h'
--- src/ui_fsmenu/launch_spg.h 2016-10-21 08:21:41 +0000
+++ src/ui_fsmenu/launch_spg.h 2016-10-29 10:23:37 +0000
@@ -20,10 +20,13 @@
20#ifndef WL_UI_FSMENU_LAUNCH_SPG_H20#ifndef WL_UI_FSMENU_LAUNCH_SPG_H
21#define WL_UI_FSMENU_LAUNCH_SPG_H21#define WL_UI_FSMENU_LAUNCH_SPG_H
2222
23#include <memory>
23#include <string>24#include <string>
2425
25#include "graphic/playercolor.h"26#include "graphic/playercolor.h"
27#include "logic/map.h"
26#include "ui_basic/button.h"28#include "ui_basic/button.h"
29#include "ui_basic/dropdown.h"
27#include "ui_basic/multilinetextarea.h"30#include "ui_basic/multilinetextarea.h"
28#include "ui_basic/textarea.h"31#include "ui_basic/textarea.h"
29#include "ui_fsmenu/base.h"32#include "ui_fsmenu/base.h"
@@ -64,9 +67,19 @@
64 LuaInterface* lua_;67 LuaInterface* lua_;
6568
66 void select_map();69 void select_map();
67 void win_condition_clicked();70 /// Loads all win conditions that can be played with the map into the selection dropdown.
68 void win_condition_update();71 /// Disables the dropdown if the map is a scenario.
69 void win_condition_load();72 void update_win_conditions();
73 /// Reads the win conditions that are available for the given map and adds the entries to the
74 /// dropdown.
75 void load_win_conditions(const Widelands::Map& map);
76 /// Remembers the win condition that is currently selected in the dropdown.
77 void win_condition_selected();
78 /// If the win condition in 'win_condition_script' can be played with the map tags,
79 /// parses the win condition and returns it as a std::unique_ptr<LuaTable>.
80 /// If this win condition can't be played with the map tags, returns a unique_ptr to nullptr.
81 std::unique_ptr<LuaTable> win_condition_if_valid(const std::string& win_condition_script,
82 std::set<std::string> tags) const;
70 void set_scenario_values();83 void set_scenario_values();
71 void switch_to_position(uint8_t);84 void switch_to_position(uint8_t);
72 void safe_place_for_host(uint8_t);85 void safe_place_for_host(uint8_t);
@@ -74,7 +87,10 @@
74 uint32_t butw_;87 uint32_t butw_;
75 uint32_t buth_;88 uint32_t buth_;
7689
77 UI::Button select_map_, wincondition_, back_, ok_;90 UI::Button select_map_;
91 UI::Dropdown<std::string> win_condition_dropdown_;
92 std::string last_win_condition_;
93 UI::Button back_, ok_;
78 UI::Button* pos_[kMaxPlayers];94 UI::Button* pos_[kMaxPlayers];
79 UI::Textarea title_, mapname_;95 UI::Textarea title_, mapname_;
80 UI::Textarea name_, type_, team_, tribe_, init_, wincondition_type_;96 UI::Textarea name_, type_, team_, tribe_, init_, wincondition_type_;
@@ -87,8 +103,6 @@
87 std::string player_save_tribe_[kMaxPlayers];103 std::string player_save_tribe_[kMaxPlayers];
88 int8_t nr_players_;104 int8_t nr_players_;
89 bool is_scenario_;105 bool is_scenario_;
90 std::vector<std::string> win_condition_scripts_;
91 uint8_t cur_wincondition_;
92};106};
93107
94#endif // end of include guard: WL_UI_FSMENU_LAUNCH_SPG_H108#endif // end of include guard: WL_UI_FSMENU_LAUNCH_SPG_H
95109
=== modified file 'src/ui_fsmenu/mapselect.cc'
--- src/ui_fsmenu/mapselect.cc 2016-10-24 14:04:00 +0000
+++ src/ui_fsmenu/mapselect.cc 2016-10-29 10:23:37 +0000
@@ -81,7 +81,8 @@
81 new UI::Box(this, tablex_, checkboxes_y_, UI::Box::Horizontal, checkbox_space_, get_w());81 new UI::Box(this, tablex_, checkboxes_y_, UI::Box::Horizontal, checkbox_space_, get_w());
8282
83 // Must be initialized before tag checkboxes83 // Must be initialized before tag checkboxes
84 cb_dont_localize_mapnames_ = new UI::Checkbox(vbox, Vector2i(0, 0), _("Show original map names"));84 cb_dont_localize_mapnames_ =
85 new UI::Checkbox(vbox, Vector2i(0, 0), _("Show original map names"));
85 cb_dont_localize_mapnames_->set_state(false);86 cb_dont_localize_mapnames_->set_state(false);
86 cb_dont_localize_mapnames_->changedto.connect(87 cb_dont_localize_mapnames_->changedto.connect(
87 boost::bind(&FullscreenMenuMapSelect::fill_table, boost::ref(*this)));88 boost::bind(&FullscreenMenuMapSelect::fill_table, boost::ref(*this)));
8889
=== modified file 'src/ui_fsmenu/options.cc'
--- src/ui_fsmenu/options.cc 2016-10-24 14:04:00 +0000
+++ src/ui_fsmenu/options.cc 2016-10-29 10:23:37 +0000
@@ -144,11 +144,20 @@
144 box_sound_(&tabs_, 0, 0, UI::Box::Vertical, 0, 0, padding_),144 box_sound_(&tabs_, 0, 0, UI::Box::Vertical, 0, 0, padding_),
145 box_saving_(&tabs_, 0, 0, UI::Box::Vertical, 0, 0, padding_),145 box_saving_(&tabs_, 0, 0, UI::Box::Vertical, 0, 0, padding_),
146 box_game_(&tabs_, 0, 0, UI::Box::Vertical, 0, 0, padding_),146 box_game_(&tabs_, 0, 0, UI::Box::Vertical, 0, 0, padding_),
147 box_language_(&tabs_, 0, 0, UI::Box::Vertical, 0, 0, padding_),
148147
149 // Interface options148 // Interface options
150 label_resolution_(&box_interface_, _("In-game resolution"), UI::Align::kLeft),149 language_dropdown_(&box_interface_,
151 resolution_list_(&box_interface_, 0, 0, column_width_ / 2, 80, true),150 0,
151 0,
152 column_width_ / 2,
153 get_inner_h() - tab_panel_y_ - buth_ - hmargin_ - 4 * padding_,
154 _("Language")),
155 resolution_dropdown_(&box_interface_,
156 0,
157 0,
158 column_width_ / 2,
159 get_inner_h() - tab_panel_y_ - 2 * buth_ - hmargin_ - 5 * padding_,
160 _("In-game resolution")),
152161
153 fullscreen_(&box_interface_, Vector2i(0, 0), _("Fullscreen"), "", column_width_),162 fullscreen_(&box_interface_, Vector2i(0, 0), _("Fullscreen"), "", column_width_),
154 inputgrab_(&box_interface_, Vector2i(0, 0), _("Grab Input"), "", column_width_),163 inputgrab_(&box_interface_, Vector2i(0, 0), _("Grab Input"), "", column_width_),
@@ -236,7 +245,8 @@
236 column_width_),245 column_width_),
237246
238 // Game options247 // Game options
239 auto_roadbuild_mode_(&box_game_, Vector2i(0, 0), _("Start building road after placing a flag")),248 auto_roadbuild_mode_(
249 &box_game_, Vector2i(0, 0), _("Start building road after placing a flag")),
240 show_workarea_preview_(&box_game_, Vector2i(0, 0), _("Show buildings area preview")),250 show_workarea_preview_(&box_game_, Vector2i(0, 0), _("Show buildings area preview")),
241 transparent_chat_(&box_game_,251 transparent_chat_(&box_game_,
242 Vector2i(0, 0),252 Vector2i(0, 0),
@@ -248,15 +258,6 @@
248 /** TRANSLATORS: and it also lets you jump to it on the map. */258 /** TRANSLATORS: and it also lets you jump to it on the map. */
249 single_watchwin_(&box_game_, Vector2i(0, 0), _("Use single watchwindow mode")),259 single_watchwin_(&box_game_, Vector2i(0, 0), _("Use single watchwindow mode")),
250260
251 // Language options
252 label_language_(&box_language_, _("Language"), UI::Align::kLeft),
253 language_list_(&box_language_,
254 0,
255 0,
256 column_width_ / 2,
257 get_inner_h() - tab_panel_y_ - 2 * buth_ - hmargin_ - 5 * padding_,
258 true),
259
260 os_(opt) {261 os_(opt) {
261 // Set up UI Elements262 // Set up UI Elements
262 title_.set_fontsize(UI_FONT_SIZE_BIG);263 title_.set_fontsize(UI_FONT_SIZE_BIG);
@@ -266,7 +267,6 @@
266 tabs_.add("options_sound", _("Sound"), &box_sound_, "");267 tabs_.add("options_sound", _("Sound"), &box_sound_, "");
267 tabs_.add("options_saving", _("Saving"), &box_saving_, "");268 tabs_.add("options_saving", _("Saving"), &box_saving_, "");
268 tabs_.add("options_game", _("Game"), &box_game_, "");269 tabs_.add("options_game", _("Game"), &box_game_, "");
269 tabs_.add("options_language", _("Language"), &box_language_, "");
270270
271 // We want the last active tab when "Apply" was clicked.271 // We want the last active tab when "Apply" was clicked.
272 if (os_.active_tab < tabs_.tabs().size()) {272 if (os_.active_tab < tabs_.tabs().size()) {
@@ -280,11 +280,10 @@
280 box_sound_.set_size(tabs_.get_inner_w(), tabs_.get_inner_h());280 box_sound_.set_size(tabs_.get_inner_w(), tabs_.get_inner_h());
281 box_saving_.set_size(tabs_.get_inner_w(), tabs_.get_inner_h());281 box_saving_.set_size(tabs_.get_inner_w(), tabs_.get_inner_h());
282 box_game_.set_size(tabs_.get_inner_w(), tabs_.get_inner_h());282 box_game_.set_size(tabs_.get_inner_w(), tabs_.get_inner_h());
283 box_language_.set_size(tabs_.get_inner_w(), tabs_.get_inner_h());
284283
285 // Interface284 // Interface
286 box_interface_.add(&label_resolution_, UI::Align::kLeft);285 box_interface_.add(&language_dropdown_, UI::Align::kLeft);
287 box_interface_.add(&resolution_list_, UI::Align::kLeft);286 box_interface_.add(&resolution_dropdown_, UI::Align::kLeft);
288 box_interface_.add(&fullscreen_, UI::Align::kLeft);287 box_interface_.add(&fullscreen_, UI::Align::kLeft);
289 box_interface_.add(&inputgrab_, UI::Align::kLeft);288 box_interface_.add(&inputgrab_, UI::Align::kLeft);
290 box_interface_.add(&sb_maxfps_, UI::Align::kLeft);289 box_interface_.add(&sb_maxfps_, UI::Align::kLeft);
@@ -312,10 +311,6 @@
312 box_game_.add(&transparent_chat_, UI::Align::kLeft);311 box_game_.add(&transparent_chat_, UI::Align::kLeft);
313 box_game_.add(&single_watchwin_, UI::Align::kLeft);312 box_game_.add(&single_watchwin_, UI::Align::kLeft);
314313
315 // Language
316 box_language_.add(&label_language_, UI::Align::kLeft);
317 box_language_.add(&language_list_, UI::Align::kLeft);
318
319 // Bind actions314 // Bind actions
320 cancel_.sigclicked.connect(boost::bind(&FullscreenMenuOptions::clicked_back, this));315 cancel_.sigclicked.connect(boost::bind(&FullscreenMenuOptions::clicked_back, this));
321 apply_.sigclicked.connect(boost::bind(&FullscreenMenuOptions::clicked_apply, this));316 apply_.sigclicked.connect(boost::bind(&FullscreenMenuOptions::clicked_apply, this));
@@ -346,18 +341,18 @@
346 for (uint32_t i = 0; i < resolutions_.size(); ++i) {341 for (uint32_t i = 0; i < resolutions_.size(); ++i) {
347 const bool selected = resolutions_[i].xres == opt.xres && resolutions_[i].yres == opt.yres;342 const bool selected = resolutions_[i].xres == opt.xres && resolutions_[i].yres == opt.yres;
348 did_select_a_res |= selected;343 did_select_a_res |= selected;
349 /** TRANSLATORS: Screen resolution, e.g. 800 x 600*/344 resolution_dropdown_.add(
350 resolution_list_.add(345 /** TRANSLATORS: Screen resolution, e.g. 800 x 600*/
351 (boost::format(_("%1% x %2%")) % resolutions_[i].xres % resolutions_[i].yres).str(),346 (boost::format(_("%1% x %2%")) % resolutions_[i].xres % resolutions_[i].yres).str(), i,
352 nullptr, nullptr, selected);347 nullptr, selected);
353 }348 }
354 if (!did_select_a_res) {349 if (!did_select_a_res) {
355 resolution_list_.add(
356 (boost::format(_("%1% x %2%")) % opt.xres % opt.yres).str(), nullptr, nullptr, true);
357 uint32_t entry = resolutions_.size();350 uint32_t entry = resolutions_.size();
358 resolutions_.resize(entry + 1);351 resolutions_.resize(entry + 1);
359 resolutions_[entry].xres = opt.xres;352 resolutions_[entry].xres = opt.xres;
360 resolutions_[entry].yres = opt.yres;353 resolutions_[entry].yres = opt.yres;
354 resolution_dropdown_.add(
355 (boost::format(_("%1% x %2%")) % opt.xres % opt.yres).str(), entry, nullptr, true);
361 }356 }
362357
363 fullscreen_.set_state(opt.fullscreen);358 fullscreen_.set_state(opt.fullscreen);
@@ -386,14 +381,13 @@
386381
387 // Language options382 // Language options
388 add_languages_to_list(opt.language);383 add_languages_to_list(opt.language);
389 language_list_.focus();
390}384}
391385
392void FullscreenMenuOptions::add_languages_to_list(const std::string& current_locale) {386void FullscreenMenuOptions::add_languages_to_list(const std::string& current_locale) {
393387
394 // We want these two entries on top - the most likely user's choice and the default.388 // We want these two entries on top - the most likely user's choice and the default.
395 language_list_.add(_("Try system language"), "", nullptr, current_locale == "");389 language_dropdown_.add(_("Try system language"), "", nullptr, current_locale == "");
396 language_list_.add("English", "en", nullptr, current_locale == "en");390 language_dropdown_.add("English", "en", nullptr, current_locale == "en");
397391
398 // Add translation directories to the list392 // Add translation directories to the list
399 std::vector<LanguageEntry> entries;393 std::vector<LanguageEntry> entries;
@@ -442,8 +436,8 @@
442 find_selected_locale(&selected_locale, current_locale);436 find_selected_locale(&selected_locale, current_locale);
443 std::sort(entries.begin(), entries.end());437 std::sort(entries.begin(), entries.end());
444 for (const LanguageEntry& entry : entries) {438 for (const LanguageEntry& entry : entries) {
445 language_list_.add(entry.descname.c_str(), entry.localename, nullptr,439 language_dropdown_.add(entry.descname.c_str(), entry.localename, nullptr,
446 entry.localename == selected_locale, "");440 entry.localename == selected_locale, "");
447 }441 }
448}442}
449443
@@ -454,9 +448,14 @@
454OptionsCtrl::OptionsStruct FullscreenMenuOptions::get_values() {448OptionsCtrl::OptionsStruct FullscreenMenuOptions::get_values() {
455 // Write all data from UI elements449 // Write all data from UI elements
456 // Interface options450 // Interface options
457 const uint32_t res_index = resolution_list_.selection_index();451 if (language_dropdown_.has_selection()) {
458 os_.xres = resolutions_[res_index].xres;452 os_.language = language_dropdown_.get_selected();
459 os_.yres = resolutions_[res_index].yres;453 }
454 if (resolution_dropdown_.has_selection()) {
455 const uint32_t res_index = resolution_dropdown_.get_selected();
456 os_.xres = resolutions_[res_index].xres;
457 os_.yres = resolutions_[res_index].yres;
458 }
460 os_.fullscreen = fullscreen_.get_state();459 os_.fullscreen = fullscreen_.get_state();
461 os_.inputgrab = inputgrab_.get_state();460 os_.inputgrab = inputgrab_.get_state();
462 os_.maxfps = sb_maxfps_.get_value();461 os_.maxfps = sb_maxfps_.get_value();
@@ -484,11 +483,6 @@
484 os_.transparent_chat = transparent_chat_.get_state();483 os_.transparent_chat = transparent_chat_.get_state();
485 os_.single_watchwin = single_watchwin_.get_state();484 os_.single_watchwin = single_watchwin_.get_state();
486485
487 // Language options
488 if (language_list_.has_selection()) {
489 os_.language = language_list_.get_selected();
490 }
491
492 // Last tab for reloading the options menu486 // Last tab for reloading the options menu
493 os_.active_tab = tabs_.active();487 os_.active_tab = tabs_.active();
494 return os_;488 return os_;
495489
=== modified file 'src/ui_fsmenu/options.h'
--- src/ui_fsmenu/options.h 2016-08-04 15:49:05 +0000
+++ src/ui_fsmenu/options.h 2016-10-29 10:23:37 +0000
@@ -27,7 +27,7 @@
2727
28#include "ui_basic/button.h"28#include "ui_basic/button.h"
29#include "ui_basic/checkbox.h"29#include "ui_basic/checkbox.h"
30#include "ui_basic/listselect.h"30#include "ui_basic/dropdown.h"
31#include "ui_basic/multilinetextarea.h"31#include "ui_basic/multilinetextarea.h"
32#include "ui_basic/spinbox.h"32#include "ui_basic/spinbox.h"
33#include "ui_basic/tabpanel.h"33#include "ui_basic/tabpanel.h"
@@ -122,11 +122,10 @@
122 UI::Box box_sound_;122 UI::Box box_sound_;
123 UI::Box box_saving_;123 UI::Box box_saving_;
124 UI::Box box_game_;124 UI::Box box_game_;
125 UI::Box box_language_;
126125
127 // Interface options126 // Interface options
128 UI::Textarea label_resolution_;127 UI::Dropdown<std::string> language_dropdown_;
129 UI::Listselect<void*> resolution_list_;128 UI::Dropdown<uintptr_t> resolution_dropdown_;
130 UI::Checkbox fullscreen_;129 UI::Checkbox fullscreen_;
131 UI::Checkbox inputgrab_;130 UI::Checkbox inputgrab_;
132 UI::SpinBox sb_maxfps_;131 UI::SpinBox sb_maxfps_;
@@ -154,10 +153,6 @@
154 UI::Checkbox transparent_chat_;153 UI::Checkbox transparent_chat_;
155 UI::Checkbox single_watchwin_;154 UI::Checkbox single_watchwin_;
156155
157 // Language options
158 UI::Textarea label_language_;
159 UI::Listselect<std::string> language_list_;
160
161 OptionsCtrl::OptionsStruct os_;156 OptionsCtrl::OptionsStruct os_;
162157
163 class ScreenResolution {158 class ScreenResolution {
164159
=== modified file 'src/wui/game_objectives_menu.cc'
--- src/wui/game_objectives_menu.cc 2016-08-04 15:49:05 +0000
+++ src/wui/game_objectives_menu.cc 2016-10-29 10:23:37 +0000
@@ -40,7 +40,7 @@
40 580,40 580,
41 5 + OBJECTIVE_LIST + 5 + FULL_OBJECTIVE_TEXT + 5 + BUTTON_HEIGHT + 5,41 5 + OBJECTIVE_LIST + 5 + FULL_OBJECTIVE_TEXT + 5 + BUTTON_HEIGHT + 5,
42 _("Objectives")),42 _("Objectives")),
43 list(this, 5, 5, get_inner_w() - 10, OBJECTIVE_LIST, false),43 list(this, 5, 5, get_inner_w() - 10, OBJECTIVE_LIST),
44 objectivetext(this,44 objectivetext(this,
45 5,45 5,
46 130,46 130,

Subscribers

People subscribed via source and target branches

to status/vote changes: