1 /*
2  * Copyright (C) 2002-2020 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 "wui/minimap.h"
21 
22 #include <memory>
23 
24 #include <SDL_mouse.h>
25 
26 #include "base/i18n.h"
27 #include "graphic/graphic.h"
28 #include "graphic/minimap_renderer.h"
29 #include "graphic/rendertarget.h"
30 #include "graphic/texture.h"
31 #include "logic/map.h"
32 #include "wui/interactive_player.h"
33 
View(UI::Panel & parent,MiniMapLayer * flags,MiniMapType * type,int32_t const x,int32_t const y,uint32_t const,uint32_t const,InteractiveBase & ibase)34 MiniMap::View::View(UI::Panel& parent,
35                     MiniMapLayer* flags,
36                     MiniMapType* type,
37                     int32_t const x,
38                     int32_t const y,
39                     uint32_t const,
40                     uint32_t const,
41                     InteractiveBase& ibase)
42    : UI::Panel(&parent, x, y, 10, 10),
43      ibase_(ibase),
44      pic_map_spot_(g_gr->images().get("images/wui/overlays/map_spot.png")),
45      minimap_layers_(flags),
46      minimap_type_(type) {
47 }
48 
set_view(const Rectf & view_area)49 void MiniMap::View::set_view(const Rectf& view_area) {
50 	view_area_ = view_area;
51 }
52 
draw(RenderTarget & dst)53 void MiniMap::View::draw(RenderTarget& dst) {
54 	minimap_image_ = draw_minimap(ibase_.egbase(), ibase_.get_player(), view_area_, *minimap_type_,
55 	                              *minimap_layers_ | MiniMapLayer::ViewWindow);
56 	dst.blit(Vector2i::zero(), minimap_image_.get());
57 }
58 
59 /*
60 ===============
61 Left-press: warp the view point to the new position
62 ===============
63 */
handle_mousepress(const uint8_t btn,int32_t x,int32_t y)64 bool MiniMap::View::handle_mousepress(const uint8_t btn, int32_t x, int32_t y) {
65 	if (btn != SDL_BUTTON_LEFT)
66 		return false;
67 
68 	dynamic_cast<MiniMap&>(*get_parent())
69 	   .warpview(minimap_pixel_to_mappixel(ibase_.egbase().map(), Vector2i(x, y), view_area_,
70 	                                       *minimap_type_, *minimap_layers_ & MiniMapLayer::Zoom2));
71 	return true;
72 }
73 
set_zoom(const bool zoom)74 void MiniMap::View::set_zoom(const bool zoom) {
75 	const Widelands::Map& map = ibase_.egbase().map();
76 	set_size(map.get_width() * scale_map(map, zoom), map.get_height() * scale_map(map, zoom));
77 }
78 
can_zoom()79 bool MiniMap::View::can_zoom() {
80 	const Widelands::Map& map = ibase_.egbase().map();
81 	// The zoomed MiniMap needs to fit into: height - windows boarders - button height. -> 60px
82 	if (scale_map(map, true) == 1 || map.get_height() * scale_map(map, true) > ibase_.get_h() - 60) {
83 		return false;
84 	}
85 	return true;
86 }
87 
88 /*
89 ==============================================================================
90 
91 MiniMap
92 
93 ==============================================================================
94 */
95 
96 /*
97 ===============
98 Initialize the minimap window. Dimensions will be set automatically
99 according to the map size.
100 A registry pointer is set to track the MiniMap object (only show one
101 minimap at a time).
102 
103 reg, the registry pointer will be set by constructor and cleared by
104 destructor
105 ===============
106 */
number_of_buttons_per_row() const107 inline uint32_t MiniMap::number_of_buttons_per_row() const {
108 	return 6;
109 }
number_of_button_rows() const110 inline uint32_t MiniMap::number_of_button_rows() const {
111 	return 1;
112 }
but_w() const113 inline uint32_t MiniMap::but_w() const {
114 	return view_.get_w() / number_of_buttons_per_row();
115 }
but_h() const116 inline uint32_t MiniMap::but_h() const {
117 	return 20;
118 }
MiniMap(InteractiveBase & ibase,Registry * const registry)119 MiniMap::MiniMap(InteractiveBase& ibase, Registry* const registry)
120    : UI::UniqueWindow(&ibase, "minimap", registry, 0, 0, _("Map")),
121      view_(*this, &registry->minimap_layers, &registry->minimap_type, 0, 0, 0, 0, ibase),
122 
123      button_terrn(this,
124                   "terrain",
125                   but_w() * 0,
126                   view_.get_h() + but_h() * 0,
127                   but_w(),
128                   but_h(),
129                   UI::ButtonStyle::kWuiSecondary,
130                   g_gr->images().get("images/wui/minimap/button_terrn.png"),
131                   _("Terrain"),
132                   UI::Button::VisualState::kRaised,
133                   UI::Button::ImageMode::kUnscaled),
134      button_owner(this,
135                   "owner",
136                   but_w() * 1,
137                   view_.get_h() + but_h() * 0,
138                   but_w(),
139                   but_h(),
140                   UI::ButtonStyle::kWuiSecondary,
141                   g_gr->images().get("images/wui/minimap/button_owner.png"),
142                   _("Owner"),
143                   UI::Button::VisualState::kRaised,
144                   UI::Button::ImageMode::kUnscaled),
145      button_flags(this,
146                   "flags",
147                   but_w() * 2,
148                   view_.get_h() + but_h() * 0,
149                   but_w(),
150                   but_h(),
151                   UI::ButtonStyle::kWuiSecondary,
152                   g_gr->images().get("images/wui/minimap/button_flags.png"),
153                   _("Flags"),
154                   UI::Button::VisualState::kRaised,
155                   UI::Button::ImageMode::kUnscaled),
156      button_roads(this,
157                   "roads",
158                   but_w() * 0,
159                   view_.get_h() + but_h() * 1,
160                   but_w(),
161                   but_h(),
162                   UI::ButtonStyle::kWuiSecondary,
163                   g_gr->images().get("images/wui/minimap/button_roads.png"),
164                   _("Roads"),
165                   UI::Button::VisualState::kRaised,
166                   UI::Button::ImageMode::kUnscaled),
167      button_bldns(this,
168                   "buildings",
169                   but_w() * 1,
170                   view_.get_h() + but_h() * 1,
171                   but_w(),
172                   but_h(),
173                   UI::ButtonStyle::kWuiSecondary,
174                   g_gr->images().get("images/wui/minimap/button_bldns.png"),
175                   _("Buildings"),
176                   UI::Button::VisualState::kRaised,
177                   UI::Button::ImageMode::kUnscaled),
178      button_zoom(this,
179                  "zoom",
180                  but_w() * 2,
181                  view_.get_h() + but_h() * 1,
182                  but_w(),
183                  but_h(),
184                  UI::ButtonStyle::kWuiSecondary,
185                  g_gr->images().get("images/wui/minimap/button_zoom.png"),
186                  _("Zoom"),
187                  UI::Button::VisualState::kRaised,
188                  UI::Button::ImageMode::kUnscaled) {
189 	button_terrn.sigclicked.connect([this]() { toggle(MiniMapLayer::Terrain); });
190 	button_owner.sigclicked.connect([this]() { toggle(MiniMapLayer::Owner); });
191 	button_flags.sigclicked.connect([this]() { toggle(MiniMapLayer::Flag); });
192 	button_roads.sigclicked.connect([this]() { toggle(MiniMapLayer::Road); });
193 	button_bldns.sigclicked.connect([this]() { toggle(MiniMapLayer::Building); });
194 	button_zoom.sigclicked.connect([this]() { toggle(MiniMapLayer::Zoom2); });
195 
196 	check_boundaries();
197 
198 	if (get_usedefaultpos())
199 		center_to_parent();
200 
201 	graphic_resolution_changed_subscriber_ = Notifications::subscribe<GraphicResolutionChanged>(
202 	   [this](const GraphicResolutionChanged&) { check_boundaries(); });
203 
204 	update_button_permpressed();
205 }
206 
toggle(MiniMapLayer const button)207 void MiniMap::toggle(MiniMapLayer const button) {
208 	*view_.minimap_layers_ = MiniMapLayer(*view_.minimap_layers_ ^ button);
209 	if (button == MiniMapLayer::Zoom2)
210 		resize();
211 	update_button_permpressed();
212 }
213 
resize()214 void MiniMap::resize() {
215 	view_.set_zoom(*view_.minimap_layers_ & MiniMapLayer::Zoom2);
216 	set_inner_size(view_.get_w(), view_.get_h() + number_of_button_rows() * but_h());
217 	button_terrn.set_pos(Vector2i(but_w() * 0, view_.get_h()));
218 	button_terrn.set_size(but_w(), but_h());
219 	button_owner.set_pos(Vector2i(but_w() * 1, view_.get_h()));
220 	button_owner.set_size(but_w(), but_h());
221 	button_flags.set_pos(Vector2i(but_w() * 2, view_.get_h()));
222 	button_flags.set_size(but_w(), but_h());
223 	button_roads.set_pos(Vector2i(but_w() * 3, view_.get_h()));
224 	button_roads.set_size(but_w(), but_h());
225 	button_bldns.set_pos(Vector2i(but_w() * 4, view_.get_h()));
226 	button_bldns.set_size(but_w(), but_h());
227 	button_zoom.set_pos(Vector2i(but_w() * 5, view_.get_h()));
228 	button_zoom.set_size(but_w(), but_h());
229 	button_zoom.set_enabled(view_.can_zoom());
230 
231 	move_inside_parent();
232 }
233 
update_button_permpressed()234 void MiniMap::update_button_permpressed() {
235 	button_terrn.set_perm_pressed(*view_.minimap_layers_ & MiniMapLayer::Terrain);
236 	button_owner.set_perm_pressed(*view_.minimap_layers_ & MiniMapLayer::Owner);
237 	button_flags.set_perm_pressed(*view_.minimap_layers_ & MiniMapLayer::Flag);
238 	button_roads.set_perm_pressed(*view_.minimap_layers_ & MiniMapLayer::Road);
239 	button_bldns.set_perm_pressed(*view_.minimap_layers_ & MiniMapLayer::Building);
240 	button_zoom.set_perm_pressed(*view_.minimap_layers_ & MiniMapLayer::Zoom2);
241 }
242 
check_boundaries()243 void MiniMap::check_boundaries() {
244 	if (!view_.can_zoom() && (*view_.minimap_layers_ & MiniMapLayer::Zoom2)) {
245 		toggle(MiniMapLayer::Zoom2);
246 	} else {
247 		resize();
248 	}
249 }
250