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, ®istry->minimap_layers, ®istry->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